From 3a42ea27a588abc1ecf5ed6464ab83316eedfdc4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 17 Apr 2026 19:56:08 +0000 Subject: [PATCH 01/22] chore(tests): bump steady to v0.22.1 --- scripts/mock | 6 +++--- scripts/test | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/mock b/scripts/mock index 5cd7c157..feebe5ed 100755 --- a/scripts/mock +++ b/scripts/mock @@ -22,9 +22,9 @@ echo "==> Starting mock server with URL ${URL}" # Run steady mock on the given spec if [ "$1" == "--daemon" ]; then # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stdy/cli@0.20.2 -- steady --version + npm exec --package=@stdy/cli@0.22.1 -- steady --version - npm exec --package=@stdy/cli@0.20.2 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" &> .stdy.log & # Wait for server to come online via health endpoint (max 30s) echo -n "Waiting for server" @@ -48,5 +48,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stdy/cli@0.20.2 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" + npm exec --package=@stdy/cli@0.22.1 -- steady --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets "$URL" fi diff --git a/scripts/test b/scripts/test index a9d718cf..19b8d0c7 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! steady_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the steady command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.20.2 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stdy/cli@0.22.1 -- steady path/to/your.openapi.yml --host 127.0.0.1 -p 4010 --validator-query-array-format=comma --validator-form-array-format=comma --validator-query-object-format=brackets --validator-form-object-format=brackets${NC}" echo exit 1 From dec3f3d0198f8caf0ed3c0851d823ea130731cc8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 10:33:57 +0000 Subject: [PATCH 02/22] chore(internal): update docs ordering --- packages/mcp-server/src/local-docs-search.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index a5b686e6..06adc9a2 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -1176,14 +1176,14 @@ const EMBEDDED_METHODS: MethodEntry[] = [ const EMBEDDED_READMES: { language: string; content: string }[] = [ { - language: 'python', + language: 'go', content: - '# Writer Python API library\n\n\n[![PyPI version](https://img.shields.io/pypi/v/writer-sdk.svg?label=pypi%20(stable))](https://pypi.org/project/writer-sdk/)\n\nThe Writer Python library provides convenient access to the Writer REST API from any Python 3.9+\napplication. The library includes type definitions for all request params and response fields,\nand offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nThe REST API documentation can be found on [dev.writer.com](https://dev.writer.com/api-guides/introduction). The full API of this library can be found in [api.md](api.md).\n\n## Installation\n\n```sh\n# install from PyPI\npip install writer-sdk\n```\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```python\nimport os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\n\nchat_completion = client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\nprint(chat_completion.id)\n```\n\nWhile you can provide an `api_key` keyword argument,\nwe recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)\nto add `WRITER_API_KEY="My API Key"` to your `.env` file\nso that your API Key is not stored in source control.\n\n## Async usage\n\nSimply import `AsyncWriter` instead of `Writer` and use `await` with each API call:\n\n```python\nimport os\nimport asyncio\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\n\nasync def main() -> None:\n chat_completion = await client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n )\n print(chat_completion.id)\n\nasyncio.run(main())\n```\n\nFunctionality between the synchronous and asynchronous clients is otherwise identical.\n\n### With aiohttp\n\nBy default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.\n\nYou can enable this by installing `aiohttp`:\n\n```sh\n# install from PyPI\npip install writer-sdk[aiohttp]\n```\n\nThen you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:\n\n```python\nimport os\nimport asyncio\nfrom writerai import DefaultAioHttpClient\nfrom writerai import AsyncWriter\n\nasync def main() -> None:\n async with AsyncWriter(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n http_client=DefaultAioHttpClient(),\n) as client:\n chat_completion = await client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n )\n print(chat_completion.id)\n\nasyncio.run(main())\n```\n\n## Streaming responses\n\nWe provide support for streaming responses using Server Side Events (SSE).\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nstream = client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n stream=True,\n)\nfor chat_completion in stream:\n print(chat_completion.id)\n```\n\nThe async client uses the exact same interface.\n\n```python\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter()\n\nstream = await client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n stream=True,\n)\nasync for chat_completion in stream:\n print(chat_completion.id)\n```\n\n## Using types\n\nNested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:\n\n- Serializing back into JSON, `model.to_json()`\n- Converting to a dictionary, `model.to_dict()`\n\nTyped requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.\n\n## Pagination\n\nList methods in the Writer API are paginated.\n\nThis library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nall_graphs = []\n# Automatically fetches more pages as needed.\nfor graph in client.graphs.list():\n # Do something with graph here\n all_graphs.append(graph)\nprint(all_graphs)\n```\n\nOr, asynchronously:\n\n```python\nimport asyncio\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter()\n\nasync def main() -> None:\n all_graphs = []\n # Iterate through items across all pages, issuing requests as needed.\n async for graph in client.graphs.list():\n all_graphs.append(graph)\n print(all_graphs)\n\nasyncio.run(main())\n```\n\nAlternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:\n\n```python\nfirst_page = await client.graphs.list()\nif first_page.has_next_page():\n print(f"will fetch next page using these details: {first_page.next_page_info()}")\n next_page = await first_page.get_next_page()\n print(f"number of items we just fetched: {len(next_page.data)}")\n\n# Remove `await` for non-async usage.\n```\n\nOr just work directly with the returned data:\n\n```python\nfirst_page = await client.graphs.list()\n\nprint(f"next page cursor: {first_page.after}") # => "next page cursor: ..."\nfor graph in first_page.data:\n print(graph.id)\n\n# Remove `await` for non-async usage.\n```\n\n## Nested params\n\nNested parameters are dictionaries, typed using `TypedDict`, for example:\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nchat_completion = client.chat.chat(\n messages=[{\n "role": "user"\n }],\n model="model",\n response_format={\n "type": "text"\n },\n)\nprint(chat_completion.response_format)\n```\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `writerai.APIConnectionError` is raised.\n\nWhen the API returns a non-success status code (that is, 4xx or 5xx\nresponse), a subclass of `writerai.APIStatusError` is raised, containing `status_code` and `response` properties.\n\nAll errors inherit from `writerai.APIError`.\n\n```python\nimport writerai\nfrom writerai import Writer\n\nclient = Writer()\n\ntry:\n client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n )\nexcept writerai.APIConnectionError as e:\n print("The server could not be reached")\n print(e.__cause__) # an underlying Exception, likely raised within httpx.\nexcept writerai.RateLimitError as e:\n print("A 429 status code was received; we should back off a bit.")\nexcept writerai.APIStatusError as e:\n print("Another non-200-range status code was received")\n print(e.status_code)\n print(e.response)\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors are automatically retried 7 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors are all retried by default.\n\nYou can use the `max_retries` option to configure or disable retry settings:\n\n```python\nfrom writerai import Writer\n\n# Configure the default for all requests:\nclient = Writer(\n # default is 2\n max_retries=0,\n)\n\n# Or, configure per-request:\nclient.with_options(max_retries = 5).chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\n```\n\n### Timeouts\n\nBy default requests time out after 3 minutes. You can configure this with a `timeout` option,\nwhich accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:\n\n```python\nfrom writerai import Writer\n\n# Configure the default for all requests:\nclient = Writer(\n # 20 seconds (default is 3 minutes)\n timeout=20.0,\n)\n\n# More granular control:\nclient = Writer(\n timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),\n)\n\n# Override per-request:\nclient.with_options(timeout = 5.0).chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\n```\n\nOn timeout, an `APITimeoutError` is thrown.\n\nNote that requests that time out are [retried twice by default](#retries).\n\n\n\n## Advanced\n\n### Logging\n\nWe use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.\n\nYou can enable logging by setting the environment variable `WRITER_LOG` to `info`.\n\n```shell\n$ export WRITER_LOG=info\n```\n\nOr to `debug` for more verbose logging.\n\n### How to tell whether `None` means `null` or missing\n\nIn an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:\n\n```py\nif response.my_field is None:\n if \'my_field\' not in response.model_fields_set:\n print(\'Got json like {}, without a "my_field" key present at all.\')\n else:\n print(\'Got json like {"my_field": null}.\')\n```\n\n### Accessing raw response data (e.g. headers)\n\nThe "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,\n\n```py\nfrom writerai import Writer\n\nclient = Writer()\nresponse = client.chat.with_raw_response.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\nprint(response.headers.get(\'X-My-Header\'))\n\nchat = response.parse() # get the object that `chat.chat()` would have returned\nprint(chat.id)\n```\n\nThese methods return an [`APIResponse`](https://github.com/writer/writer-python/tree/main/src/writerai/_response.py) object.\n\nThe async client returns an [`AsyncAPIResponse`](https://github.com/writer/writer-python/tree/main/src/writerai/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.\n\n#### `.with_streaming_response`\n\nThe above interface eagerly reads the full response body when you make the request, which may not always be what you want.\n\nTo stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.\n\n```python\nwith client.chat.with_streaming_response.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n) as response :\n print(response.headers.get(\'X-My-Header\'))\n\n for line in response.iter_lines():\n print(line)\n```\n\nThe context manager is required so that the response will reliably be closed.\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API.\n\nIf you need to access undocumented endpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other\nhttp verbs. Options on the client will be respected (such as retries) when making this request.\n\n```py\nimport httpx\n\nresponse = client.post(\n "/foo",\n cast_to=httpx.Response,\n body={"my_param": True},\n)\n\nprint(response.headers.get("x-foo"))\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You\ncan also get all the extra fields on the Pydantic model as a dict with\n[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).\n\n### Configuring the HTTP client\n\nYou can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:\n\n- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)\n- Custom [transports](https://www.python-httpx.org/advanced/transports/)\n- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality\n\n```python\nimport httpx\nfrom writerai import Writer, DefaultHttpxClient\n\nclient = Writer(\n # Or use the `WRITER_BASE_URL` env var\n base_url="http://my.test.server.example.com:8083",\n http_client=DefaultHttpxClient(proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0")),\n)\n```\n\nYou can also customize the client on a per-request basis by using `with_options()`:\n\n```python\nclient.with_options(http_client=DefaultHttpxClient(...))\n```\n\n### Managing HTTP resources\n\nBy default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.\n\n```py\nfrom writerai import Writer\n\nwith Writer() as client:\n # make requests here\n ...\n\n# HTTP client is now closed\n```\n\n## Versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/writer/writer-python/issues) with questions, bugs, or suggestions.\n\n### Determining the installed version\n\nIf you\'ve upgraded to the latest version but aren\'t seeing any new features you were expecting then your python environment is likely still using an older version.\n\nYou can determine the version that is being used at runtime with:\n\n```py\nimport writerai\nprint(writerai.__version__)\n```\n\n## Requirements\n\nPython 3.9 or higher.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n', + '# Writer Go API Library\n\nGo Reference\n\nThe Writer Go library provides convenient access to the [Writer REST API](https://dev.writer.com/api-guides/introduction)\nfrom applications written in Go.\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n\n\n```go\nimport (\n\t"github.com/stainless-sdks/writer-go" // imported as SDK_PackageName\n)\n```\n\n\n\nOr to pin the version:\n\n\n\n```sh\ngo get -u \'github.com/stainless-sdks/writer-go@v0.0.1\'\n```\n\n\n\n## Requirements\n\nThis library requires Go 1.22+.\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```go\npackage main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n\t"github.com/stainless-sdks/writer-go/shared"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"), // defaults to os.LookupEnv("WRITER_API_KEY")\n\t)\n\tchatCompletion, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chatCompletion.ID)\n}\n\n```\n\n### Request fields\n\nAll request parameters are wrapped in a generic `Field` type,\nwhich we use to distinguish zero values from null or omitted fields.\n\nThis prevents accidentally sending a zero value if you forget a required parameter,\nand enables explicitly sending `null`, `false`, `\'\'`, or `0` on optional parameters.\nAny field not specified is not sent.\n\nTo construct fields with values, use the helpers `String()`, `Int()`, `Float()`, or most commonly, the generic `F[T]()`.\nTo send a null, use `Null[T]()`, and to send a nonconforming value, use `Raw[T](any)`. For example:\n\n```go\nparams := FooParams{\n\tName: SDK_PackageName.F("hello"),\n\n\t// Explicitly send `"description": null`\n\tDescription: SDK_PackageName.Null[string](),\n\n\tPoint: SDK_PackageName.F(SDK_PackageName.Point{\n\t\tX: SDK_PackageName.Int(0),\n\t\tY: SDK_PackageName.Int(1),\n\n\t\t// In cases where the API specifies a given type,\n\t\t// but you want to send something else, use `Raw`:\n\t\tZ: SDK_PackageName.Raw[int64](0.01), // sends a float\n\t}),\n}\n```\n\n### Response objects\n\nAll fields in response structs are value types (not pointers or wrappers).\n\nIf a given field is `null`, not present, or invalid, the corresponding field\nwill simply be its zero value.\n\nAll response structs also include a special `JSON` field, containing more detailed\ninformation about each property, which you can use like so:\n\n```go\nif res.Name == "" {\n\t// true if `"name"` is either not present or explicitly null\n\tres.JSON.Name.IsNull()\n\n\t// true if the `"name"` key was not present in the response JSON at all\n\tres.JSON.Name.IsMissing()\n\n\t// When the API returns data that cannot be coerced to the expected type:\n\tif res.JSON.Name.IsInvalid() {\n\t\traw := res.JSON.Name.Raw()\n\n\t\tlegacyName := struct{\n\t\t\tFirst string `json:"first"`\n\t\t\tLast string `json:"last"`\n\t\t}{}\n\t\tjson.Unmarshal([]byte(raw), &legacyName)\n\t\tname = legacyName.First + " " + legacyName.Last\n\t}\n}\n```\n\nThese `.JSON` structs also include an `Extras` map containing\nany properties in the json response that were not specified\nin the struct. This can be useful for API features not yet\npresent in the SDK.\n\n```go\nbody := res.JSON.ExtraFields["my_unexpected_field"].Raw()\n```\n\n### RequestOptions\n\nThis library uses the functional options pattern. Functions defined in the\n`SDK_PackageOptionName` package return a `RequestOption`, which is a closure that mutates a\n`RequestConfig`. These options can be supplied to the client or at individual\nrequests. For example:\n\n```go\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\t// Adds a header to every request made by the client\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "custom_header_info"),\n)\n\nclient.Chat.Chat(context.TODO(), ...,\n\t// Override the header\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "some_other_custom_header_info"),\n\t// Add an undocumented field to the request body, using sjson syntax\n\tSDK_PackageOptionName.WithJSONSet("some.json.path", map[string]string{"my": "object"}),\n)\n```\n\nSee the [full list of request options](https://pkg.go.dev/github.com/stainless-sdks/writer-go/SDK_PackageOptionName).\n\n### Pagination\n\nThis library provides some conveniences for working with paginated list endpoints.\n\nYou can use `.ListAutoPaging()` methods to iterate through items across all pages:\n\n```go\niter := client.Graphs.ListAutoPaging(context.TODO(), writersdk.GraphListParams{})\n// Automatically fetches more pages as needed.\nfor iter.Next() {\n\tgraph := iter.Current()\n\tfmt.Printf("%+v\\n", graph)\n}\nif err := iter.Err(); err != nil {\n\tpanic(err.Error())\n}\n```\n\nOr you can use simple `.List()` methods to fetch a single page and receive a standard response object\nwith additional helper methods like `.GetNextPage()`, e.g.:\n\n```go\npage, err := client.Graphs.List(context.TODO(), writersdk.GraphListParams{})\nfor page != nil {\n\tfor _, graph := range page.Data {\n\t\tfmt.Printf("%+v\\n", graph)\n\t}\n\tpage, err = page.GetNextPage()\n}\nif err != nil {\n\tpanic(err.Error())\n}\n```\n\n### Errors\n\nWhen the API returns a non-success status code, we return an error with type\n`*SDK_PackageName.Error`. This contains the `StatusCode`, `*http.Request`, and\n`*http.Response` values of the request, as well as the JSON of the error body\n(much like other response objects in the SDK).\n\nTo handle errors, we recommend that you use the `errors.As` pattern:\n\n```go\n_, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t}}),\n\tModel: writersdk.F("palmyra-x5"),\n})\nif err != nil {\n\tvar apierr *writersdk.Error\n\tif errors.As(err, &apierr) {\n\t\tprintln(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request\n\t\tprintln(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response\n\t}\n\tpanic(err.Error()) // GET "/v1/chat": 400 Bad Request { ... }\n}\n```\n\nWhen other errors occur, they are returned unwrapped; for example,\nif HTTP transport fails, you might receive `*url.Error` wrapping `*net.OpError`.\n\n### Timeouts\n\nRequests do not time out by default; use context to configure a timeout for a request lifecycle.\n\nNote that if a request is [retried](#retries), the context timeout does not start over.\nTo set a per-retry timeout, use `SDK_PackageOptionName.WithRequestTimeout()`.\n\n```go\n// This sets the timeout for the request, including all the retries.\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)\ndefer cancel()\nclient.Chat.Chat(\n\tctx,\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t},\n\t// This sets the per-retry timeout\n\toption.WithRequestTimeout(20*time.Second),\n)\n```\n\n### File uploads\n\nRequest parameters that correspond to file uploads in multipart requests are typed as\n`param.Field[io.Reader]`. The contents of the `io.Reader` will by default be sent as a multipart form\npart with the file name of "anonymous_file" and content-type of "application/octet-stream".\n\nThe file name and content-type can be customized by implementing `Name() string` or `ContentType()\nstring` on the run-time type of `io.Reader`. Note that `os.File` implements `Name() string`, so a\nfile returned by `os.Open` will be sent with the file name on disk.\n\nWe also provide a helper `SDK_PackageName.FileParam(reader io.Reader, filename string, contentType string)`\nwhich can be used to wrap any `io.Reader` with the appropriate file name and content type.\n\n\n\n### Retries\n\nCertain errors will be automatically retried 7 times by default, with a short exponential backoff.\nWe retry by default all connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit,\nand >=500 Internal errors.\n\nYou can use the `WithMaxRetries` option to configure or disable this:\n\n```go\n// Configure the default for all requests:\nclient := writersdk.NewClient(\n\toption.WithMaxRetries(0), // default is 2\n)\n\n// Override per-request:\nclient.Chat.Chat(\n\tcontext.TODO(),\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t},\n\toption.WithMaxRetries(5),\n)\n```\n\n\n### Accessing raw response data (e.g. response headers)\n\nYou can access the raw HTTP response data by using the `option.WithResponseInto()` request option. This is useful when\nyou need to examine response headers, status codes, or other details.\n\n```go\n// Create a variable to store the HTTP response\nvar response *http.Response\nchatCompletion, err := client.Chat.Chat(\n\tcontext.TODO(),\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t},\n\toption.WithResponseInto(&response),\n)\nif err != nil {\n\t// handle error\n}\nfmt.Printf("%+v\\n", chatCompletion)\n\nfmt.Printf("Status Code: %d\\n", response.StatusCode)\nfmt.Printf("Headers: %+#v\\n", response.Header)\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.Get`, `client.Post`, and other HTTP verbs.\n`RequestOptions` on the client, such as retries, will be respected when making these requests.\n\n```go\nvar (\n // params can be an io.Reader, a []byte, an encoding/json serializable object,\n // or a "…Params" struct defined in this library.\n params map[string]interface{}\n\n // result can be an []byte, *http.Response, a encoding/json deserializable object,\n // or a model defined in this library.\n result *http.Response\n)\nerr := client.Post(context.Background(), "/unspecified", params, &result)\nif err != nil {\n …\n}\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use either the `SDK_PackageOptionName.WithQuerySet()`\nor the `SDK_PackageOptionName.WithJSONSet()` methods.\n\n```go\nparams := FooNewParams{\n ID: SDK_PackageName.F("id_xxxx"),\n Data: SDK_PackageName.F(FooNewParamsData{\n FirstName: SDK_PackageName.F("John"),\n }),\n}\nclient.Foo.New(context.Background(), params, SDK_PackageOptionName.WithJSONSet("data.last_name", "Doe"))\n```\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may either access the raw JSON of the response as a string\nwith `result.JSON.RawJSON()`, or get the raw JSON of a particular field on the result with\n`result.JSON.Foo.Raw()`.\n\nAny fields that are not present on the response struct will be saved and can be accessed by `result.JSON.ExtraFields()` which returns the extra fields as a `map[string]Field`.\n\n### Middleware\n\nWe provide `SDK_PackageOptionName.WithMiddleware` which applies the given\nmiddleware to requests.\n\n```go\nfunc Logger(req *http.Request, next SDK_PackageOptionName.MiddlewareNext) (res *http.Response, err error) {\n\t// Before the request\n\tstart := time.Now()\n\tLogReq(req)\n\n\t// Forward the request to the next handler\n\tres, err = next(req)\n\n\t// Handle stuff after the request\n\tend := time.Now()\n\tLogRes(res, err, start - end)\n\n return res, err\n}\n\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\tSDK_PackageOptionName.WithMiddleware(Logger),\n)\n```\n\nWhen multiple middlewares are provided as variadic arguments, the middlewares\nare applied left to right. If `SDK_PackageOptionName.WithMiddleware` is given\nmultiple times, for example first in the client then the method, the\nmiddleware in the client will run first and the middleware given in the method\nwill run next.\n\nYou may also replace the default `http.Client` with\n`SDK_PackageOptionName.WithHTTPClient(client)`. Only one http client is\naccepted (this overwrites any previous client) and receives requests after any\nmiddleware has been applied.\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/writer-go/issues) with questions, bugs, or suggestions.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n', }, { - language: 'go', + language: 'python', content: - '# Writer Go API Library\n\nGo Reference\n\nThe Writer Go library provides convenient access to the [Writer REST API](https://dev.writer.com/api-guides/introduction)\nfrom applications written in Go.\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n\n\n```go\nimport (\n\t"github.com/stainless-sdks/writer-go" // imported as SDK_PackageName\n)\n```\n\n\n\nOr to pin the version:\n\n\n\n```sh\ngo get -u \'github.com/stainless-sdks/writer-go@v0.0.1\'\n```\n\n\n\n## Requirements\n\nThis library requires Go 1.22+.\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```go\npackage main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n\t"github.com/stainless-sdks/writer-go/shared"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"), // defaults to os.LookupEnv("WRITER_API_KEY")\n\t)\n\tchatCompletion, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chatCompletion.ID)\n}\n\n```\n\n### Request fields\n\nAll request parameters are wrapped in a generic `Field` type,\nwhich we use to distinguish zero values from null or omitted fields.\n\nThis prevents accidentally sending a zero value if you forget a required parameter,\nand enables explicitly sending `null`, `false`, `\'\'`, or `0` on optional parameters.\nAny field not specified is not sent.\n\nTo construct fields with values, use the helpers `String()`, `Int()`, `Float()`, or most commonly, the generic `F[T]()`.\nTo send a null, use `Null[T]()`, and to send a nonconforming value, use `Raw[T](any)`. For example:\n\n```go\nparams := FooParams{\n\tName: SDK_PackageName.F("hello"),\n\n\t// Explicitly send `"description": null`\n\tDescription: SDK_PackageName.Null[string](),\n\n\tPoint: SDK_PackageName.F(SDK_PackageName.Point{\n\t\tX: SDK_PackageName.Int(0),\n\t\tY: SDK_PackageName.Int(1),\n\n\t\t// In cases where the API specifies a given type,\n\t\t// but you want to send something else, use `Raw`:\n\t\tZ: SDK_PackageName.Raw[int64](0.01), // sends a float\n\t}),\n}\n```\n\n### Response objects\n\nAll fields in response structs are value types (not pointers or wrappers).\n\nIf a given field is `null`, not present, or invalid, the corresponding field\nwill simply be its zero value.\n\nAll response structs also include a special `JSON` field, containing more detailed\ninformation about each property, which you can use like so:\n\n```go\nif res.Name == "" {\n\t// true if `"name"` is either not present or explicitly null\n\tres.JSON.Name.IsNull()\n\n\t// true if the `"name"` key was not present in the response JSON at all\n\tres.JSON.Name.IsMissing()\n\n\t// When the API returns data that cannot be coerced to the expected type:\n\tif res.JSON.Name.IsInvalid() {\n\t\traw := res.JSON.Name.Raw()\n\n\t\tlegacyName := struct{\n\t\t\tFirst string `json:"first"`\n\t\t\tLast string `json:"last"`\n\t\t}{}\n\t\tjson.Unmarshal([]byte(raw), &legacyName)\n\t\tname = legacyName.First + " " + legacyName.Last\n\t}\n}\n```\n\nThese `.JSON` structs also include an `Extras` map containing\nany properties in the json response that were not specified\nin the struct. This can be useful for API features not yet\npresent in the SDK.\n\n```go\nbody := res.JSON.ExtraFields["my_unexpected_field"].Raw()\n```\n\n### RequestOptions\n\nThis library uses the functional options pattern. Functions defined in the\n`SDK_PackageOptionName` package return a `RequestOption`, which is a closure that mutates a\n`RequestConfig`. These options can be supplied to the client or at individual\nrequests. For example:\n\n```go\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\t// Adds a header to every request made by the client\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "custom_header_info"),\n)\n\nclient.Chat.Chat(context.TODO(), ...,\n\t// Override the header\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "some_other_custom_header_info"),\n\t// Add an undocumented field to the request body, using sjson syntax\n\tSDK_PackageOptionName.WithJSONSet("some.json.path", map[string]string{"my": "object"}),\n)\n```\n\nSee the [full list of request options](https://pkg.go.dev/github.com/stainless-sdks/writer-go/SDK_PackageOptionName).\n\n### Pagination\n\nThis library provides some conveniences for working with paginated list endpoints.\n\nYou can use `.ListAutoPaging()` methods to iterate through items across all pages:\n\n```go\niter := client.Graphs.ListAutoPaging(context.TODO(), writersdk.GraphListParams{})\n// Automatically fetches more pages as needed.\nfor iter.Next() {\n\tgraph := iter.Current()\n\tfmt.Printf("%+v\\n", graph)\n}\nif err := iter.Err(); err != nil {\n\tpanic(err.Error())\n}\n```\n\nOr you can use simple `.List()` methods to fetch a single page and receive a standard response object\nwith additional helper methods like `.GetNextPage()`, e.g.:\n\n```go\npage, err := client.Graphs.List(context.TODO(), writersdk.GraphListParams{})\nfor page != nil {\n\tfor _, graph := range page.Data {\n\t\tfmt.Printf("%+v\\n", graph)\n\t}\n\tpage, err = page.GetNextPage()\n}\nif err != nil {\n\tpanic(err.Error())\n}\n```\n\n### Errors\n\nWhen the API returns a non-success status code, we return an error with type\n`*SDK_PackageName.Error`. This contains the `StatusCode`, `*http.Request`, and\n`*http.Response` values of the request, as well as the JSON of the error body\n(much like other response objects in the SDK).\n\nTo handle errors, we recommend that you use the `errors.As` pattern:\n\n```go\n_, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t}}),\n\tModel: writersdk.F("palmyra-x5"),\n})\nif err != nil {\n\tvar apierr *writersdk.Error\n\tif errors.As(err, &apierr) {\n\t\tprintln(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request\n\t\tprintln(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response\n\t}\n\tpanic(err.Error()) // GET "/v1/chat": 400 Bad Request { ... }\n}\n```\n\nWhen other errors occur, they are returned unwrapped; for example,\nif HTTP transport fails, you might receive `*url.Error` wrapping `*net.OpError`.\n\n### Timeouts\n\nRequests do not time out by default; use context to configure a timeout for a request lifecycle.\n\nNote that if a request is [retried](#retries), the context timeout does not start over.\nTo set a per-retry timeout, use `SDK_PackageOptionName.WithRequestTimeout()`.\n\n```go\n// This sets the timeout for the request, including all the retries.\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)\ndefer cancel()\nclient.Chat.Chat(\n\tctx,\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t},\n\t// This sets the per-retry timeout\n\toption.WithRequestTimeout(20*time.Second),\n)\n```\n\n### File uploads\n\nRequest parameters that correspond to file uploads in multipart requests are typed as\n`param.Field[io.Reader]`. The contents of the `io.Reader` will by default be sent as a multipart form\npart with the file name of "anonymous_file" and content-type of "application/octet-stream".\n\nThe file name and content-type can be customized by implementing `Name() string` or `ContentType()\nstring` on the run-time type of `io.Reader`. Note that `os.File` implements `Name() string`, so a\nfile returned by `os.Open` will be sent with the file name on disk.\n\nWe also provide a helper `SDK_PackageName.FileParam(reader io.Reader, filename string, contentType string)`\nwhich can be used to wrap any `io.Reader` with the appropriate file name and content type.\n\n\n\n### Retries\n\nCertain errors will be automatically retried 7 times by default, with a short exponential backoff.\nWe retry by default all connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit,\nand >=500 Internal errors.\n\nYou can use the `WithMaxRetries` option to configure or disable this:\n\n```go\n// Configure the default for all requests:\nclient := writersdk.NewClient(\n\toption.WithMaxRetries(0), // default is 2\n)\n\n// Override per-request:\nclient.Chat.Chat(\n\tcontext.TODO(),\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t},\n\toption.WithMaxRetries(5),\n)\n```\n\n\n### Accessing raw response data (e.g. response headers)\n\nYou can access the raw HTTP response data by using the `option.WithResponseInto()` request option. This is useful when\nyou need to examine response headers, status codes, or other details.\n\n```go\n// Create a variable to store the HTTP response\nvar response *http.Response\nchatCompletion, err := client.Chat.Chat(\n\tcontext.TODO(),\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t},\n\toption.WithResponseInto(&response),\n)\nif err != nil {\n\t// handle error\n}\nfmt.Printf("%+v\\n", chatCompletion)\n\nfmt.Printf("Status Code: %d\\n", response.StatusCode)\nfmt.Printf("Headers: %+#v\\n", response.Header)\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.Get`, `client.Post`, and other HTTP verbs.\n`RequestOptions` on the client, such as retries, will be respected when making these requests.\n\n```go\nvar (\n // params can be an io.Reader, a []byte, an encoding/json serializable object,\n // or a "…Params" struct defined in this library.\n params map[string]interface{}\n\n // result can be an []byte, *http.Response, a encoding/json deserializable object,\n // or a model defined in this library.\n result *http.Response\n)\nerr := client.Post(context.Background(), "/unspecified", params, &result)\nif err != nil {\n …\n}\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use either the `SDK_PackageOptionName.WithQuerySet()`\nor the `SDK_PackageOptionName.WithJSONSet()` methods.\n\n```go\nparams := FooNewParams{\n ID: SDK_PackageName.F("id_xxxx"),\n Data: SDK_PackageName.F(FooNewParamsData{\n FirstName: SDK_PackageName.F("John"),\n }),\n}\nclient.Foo.New(context.Background(), params, SDK_PackageOptionName.WithJSONSet("data.last_name", "Doe"))\n```\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may either access the raw JSON of the response as a string\nwith `result.JSON.RawJSON()`, or get the raw JSON of a particular field on the result with\n`result.JSON.Foo.Raw()`.\n\nAny fields that are not present on the response struct will be saved and can be accessed by `result.JSON.ExtraFields()` which returns the extra fields as a `map[string]Field`.\n\n### Middleware\n\nWe provide `SDK_PackageOptionName.WithMiddleware` which applies the given\nmiddleware to requests.\n\n```go\nfunc Logger(req *http.Request, next SDK_PackageOptionName.MiddlewareNext) (res *http.Response, err error) {\n\t// Before the request\n\tstart := time.Now()\n\tLogReq(req)\n\n\t// Forward the request to the next handler\n\tres, err = next(req)\n\n\t// Handle stuff after the request\n\tend := time.Now()\n\tLogRes(res, err, start - end)\n\n return res, err\n}\n\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\tSDK_PackageOptionName.WithMiddleware(Logger),\n)\n```\n\nWhen multiple middlewares are provided as variadic arguments, the middlewares\nare applied left to right. If `SDK_PackageOptionName.WithMiddleware` is given\nmultiple times, for example first in the client then the method, the\nmiddleware in the client will run first and the middleware given in the method\nwill run next.\n\nYou may also replace the default `http.Client` with\n`SDK_PackageOptionName.WithHTTPClient(client)`. Only one http client is\naccepted (this overwrites any previous client) and receives requests after any\nmiddleware has been applied.\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/writer-go/issues) with questions, bugs, or suggestions.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n', + '# Writer Python API library\n\n\n[![PyPI version](https://img.shields.io/pypi/v/writer-sdk.svg?label=pypi%20(stable))](https://pypi.org/project/writer-sdk/)\n\nThe Writer Python library provides convenient access to the Writer REST API from any Python 3.9+\napplication. The library includes type definitions for all request params and response fields,\nand offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nThe REST API documentation can be found on [dev.writer.com](https://dev.writer.com/api-guides/introduction). The full API of this library can be found in [api.md](api.md).\n\n## Installation\n\n```sh\n# install from PyPI\npip install writer-sdk\n```\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```python\nimport os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\n\nchat_completion = client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\nprint(chat_completion.id)\n```\n\nWhile you can provide an `api_key` keyword argument,\nwe recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)\nto add `WRITER_API_KEY="My API Key"` to your `.env` file\nso that your API Key is not stored in source control.\n\n## Async usage\n\nSimply import `AsyncWriter` instead of `Writer` and use `await` with each API call:\n\n```python\nimport os\nimport asyncio\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\n\nasync def main() -> None:\n chat_completion = await client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n )\n print(chat_completion.id)\n\nasyncio.run(main())\n```\n\nFunctionality between the synchronous and asynchronous clients is otherwise identical.\n\n### With aiohttp\n\nBy default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.\n\nYou can enable this by installing `aiohttp`:\n\n```sh\n# install from PyPI\npip install writer-sdk[aiohttp]\n```\n\nThen you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:\n\n```python\nimport os\nimport asyncio\nfrom writerai import DefaultAioHttpClient\nfrom writerai import AsyncWriter\n\nasync def main() -> None:\n async with AsyncWriter(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n http_client=DefaultAioHttpClient(),\n) as client:\n chat_completion = await client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n )\n print(chat_completion.id)\n\nasyncio.run(main())\n```\n\n## Streaming responses\n\nWe provide support for streaming responses using Server Side Events (SSE).\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nstream = client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n stream=True,\n)\nfor chat_completion in stream:\n print(chat_completion.id)\n```\n\nThe async client uses the exact same interface.\n\n```python\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter()\n\nstream = await client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n stream=True,\n)\nasync for chat_completion in stream:\n print(chat_completion.id)\n```\n\n## Using types\n\nNested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:\n\n- Serializing back into JSON, `model.to_json()`\n- Converting to a dictionary, `model.to_dict()`\n\nTyped requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.\n\n## Pagination\n\nList methods in the Writer API are paginated.\n\nThis library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nall_graphs = []\n# Automatically fetches more pages as needed.\nfor graph in client.graphs.list():\n # Do something with graph here\n all_graphs.append(graph)\nprint(all_graphs)\n```\n\nOr, asynchronously:\n\n```python\nimport asyncio\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter()\n\nasync def main() -> None:\n all_graphs = []\n # Iterate through items across all pages, issuing requests as needed.\n async for graph in client.graphs.list():\n all_graphs.append(graph)\n print(all_graphs)\n\nasyncio.run(main())\n```\n\nAlternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:\n\n```python\nfirst_page = await client.graphs.list()\nif first_page.has_next_page():\n print(f"will fetch next page using these details: {first_page.next_page_info()}")\n next_page = await first_page.get_next_page()\n print(f"number of items we just fetched: {len(next_page.data)}")\n\n# Remove `await` for non-async usage.\n```\n\nOr just work directly with the returned data:\n\n```python\nfirst_page = await client.graphs.list()\n\nprint(f"next page cursor: {first_page.after}") # => "next page cursor: ..."\nfor graph in first_page.data:\n print(graph.id)\n\n# Remove `await` for non-async usage.\n```\n\n## Nested params\n\nNested parameters are dictionaries, typed using `TypedDict`, for example:\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nchat_completion = client.chat.chat(\n messages=[{\n "role": "user"\n }],\n model="model",\n response_format={\n "type": "text"\n },\n)\nprint(chat_completion.response_format)\n```\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `writerai.APIConnectionError` is raised.\n\nWhen the API returns a non-success status code (that is, 4xx or 5xx\nresponse), a subclass of `writerai.APIStatusError` is raised, containing `status_code` and `response` properties.\n\nAll errors inherit from `writerai.APIError`.\n\n```python\nimport writerai\nfrom writerai import Writer\n\nclient = Writer()\n\ntry:\n client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n )\nexcept writerai.APIConnectionError as e:\n print("The server could not be reached")\n print(e.__cause__) # an underlying Exception, likely raised within httpx.\nexcept writerai.RateLimitError as e:\n print("A 429 status code was received; we should back off a bit.")\nexcept writerai.APIStatusError as e:\n print("Another non-200-range status code was received")\n print(e.status_code)\n print(e.response)\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors are automatically retried 7 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors are all retried by default.\n\nYou can use the `max_retries` option to configure or disable retry settings:\n\n```python\nfrom writerai import Writer\n\n# Configure the default for all requests:\nclient = Writer(\n # default is 2\n max_retries=0,\n)\n\n# Or, configure per-request:\nclient.with_options(max_retries = 5).chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\n```\n\n### Timeouts\n\nBy default requests time out after 3 minutes. You can configure this with a `timeout` option,\nwhich accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:\n\n```python\nfrom writerai import Writer\n\n# Configure the default for all requests:\nclient = Writer(\n # 20 seconds (default is 3 minutes)\n timeout=20.0,\n)\n\n# More granular control:\nclient = Writer(\n timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),\n)\n\n# Override per-request:\nclient.with_options(timeout = 5.0).chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\n```\n\nOn timeout, an `APITimeoutError` is thrown.\n\nNote that requests that time out are [retried twice by default](#retries).\n\n\n\n## Advanced\n\n### Logging\n\nWe use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.\n\nYou can enable logging by setting the environment variable `WRITER_LOG` to `info`.\n\n```shell\n$ export WRITER_LOG=info\n```\n\nOr to `debug` for more verbose logging.\n\n### How to tell whether `None` means `null` or missing\n\nIn an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:\n\n```py\nif response.my_field is None:\n if \'my_field\' not in response.model_fields_set:\n print(\'Got json like {}, without a "my_field" key present at all.\')\n else:\n print(\'Got json like {"my_field": null}.\')\n```\n\n### Accessing raw response data (e.g. headers)\n\nThe "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,\n\n```py\nfrom writerai import Writer\n\nclient = Writer()\nresponse = client.chat.with_raw_response.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\nprint(response.headers.get(\'X-My-Header\'))\n\nchat = response.parse() # get the object that `chat.chat()` would have returned\nprint(chat.id)\n```\n\nThese methods return an [`APIResponse`](https://github.com/writer/writer-python/tree/main/src/writerai/_response.py) object.\n\nThe async client returns an [`AsyncAPIResponse`](https://github.com/writer/writer-python/tree/main/src/writerai/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.\n\n#### `.with_streaming_response`\n\nThe above interface eagerly reads the full response body when you make the request, which may not always be what you want.\n\nTo stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.\n\n```python\nwith client.chat.with_streaming_response.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n) as response :\n print(response.headers.get(\'X-My-Header\'))\n\n for line in response.iter_lines():\n print(line)\n```\n\nThe context manager is required so that the response will reliably be closed.\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API.\n\nIf you need to access undocumented endpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other\nhttp verbs. Options on the client will be respected (such as retries) when making this request.\n\n```py\nimport httpx\n\nresponse = client.post(\n "/foo",\n cast_to=httpx.Response,\n body={"my_param": True},\n)\n\nprint(response.headers.get("x-foo"))\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You\ncan also get all the extra fields on the Pydantic model as a dict with\n[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).\n\n### Configuring the HTTP client\n\nYou can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:\n\n- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)\n- Custom [transports](https://www.python-httpx.org/advanced/transports/)\n- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality\n\n```python\nimport httpx\nfrom writerai import Writer, DefaultHttpxClient\n\nclient = Writer(\n # Or use the `WRITER_BASE_URL` env var\n base_url="http://my.test.server.example.com:8083",\n http_client=DefaultHttpxClient(proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0")),\n)\n```\n\nYou can also customize the client on a per-request basis by using `with_options()`:\n\n```python\nclient.with_options(http_client=DefaultHttpxClient(...))\n```\n\n### Managing HTTP resources\n\nBy default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.\n\n```py\nfrom writerai import Writer\n\nwith Writer() as client:\n # make requests here\n ...\n\n# HTTP client is now closed\n```\n\n## Versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/writer/writer-python/issues) with questions, bugs, or suggestions.\n\n### Determining the installed version\n\nIf you\'ve upgraded to the latest version but aren\'t seeing any new features you were expecting then your python environment is likely still using an older version.\n\nYou can determine the version that is being used at runtime with:\n\n```py\nimport writerai\nprint(writerai.__version__)\n```\n\n## Requirements\n\nPython 3.9 or higher.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n', }, { language: 'typescript', From af77915717a2749b0275b3fc9c1a09f4c69826ce Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 22 Apr 2026 13:59:34 +0000 Subject: [PATCH 03/22] chore(internal): more robust bootstrap script --- scripts/bootstrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/bootstrap b/scripts/bootstrap index a8b69ff3..2e315f53 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,7 +4,7 @@ set -e cd "$(dirname "$0")/.." -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "${SKIP_BREW:-}" != "1" ] && [ -t 0 ]; then brew bundle check >/dev/null 2>&1 || { echo -n "==> Install Homebrew dependencies? (y/N): " read -r response From 6eeaf254b4afdffe9244423b9528dae85392db45 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 13:34:22 +0000 Subject: [PATCH 04/22] chore: restructure docs search code --- packages/mcp-server/src/local-docs-search.ts | 594 +++++++++---------- 1 file changed, 297 insertions(+), 297 deletions(-) diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 06adc9a2..f90a9750 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -64,24 +64,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## generate_content\n\n`client.applications.generateContent(application_id: string, inputs: { id: string; value: string[]; }[], stream?: boolean): { suggestion: string; title?: string; }`\n\n**post** `/v1/applications/{application_id}`\n\nGenerate content from an existing no-code agent (formerly called no-code applications) with inputs.\n\n### Parameters\n\n- `application_id: string`\n\n- `inputs: { id: string; value: string[]; }[]`\n\n- `stream?: boolean`\n Indicates whether the response should be streamed. Currently only supported for research assistant applications.\n\n### Returns\n\n- `{ suggestion: string; title?: string; }`\n\n - `suggestion: string`\n - `title?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.applications.generateContent('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { inputs: [{ id: 'id', value: ['string'] }] });\nfor await (const applicationGenerateContentChunk of stream) {\n console.log(applicationGenerateContentChunk);\n}\n```", perLanguage: { - go: { - method: 'client.Applications.GenerateContent', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGenerateContentResponse, err := client.Applications.GenerateContent(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\twritersdk.ApplicationGenerateContentParams{\n\t\t\tInputs: writersdk.F([]writersdk.ApplicationGenerateContentParamsInput{{\n\t\t\t\tID: writersdk.F("id"),\n\t\t\t\tValue: writersdk.F([]string{"string"}),\n\t\t\t}}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGenerateContentResponse.Suggestion)\n}\n', - }, - http: { + typescript: { + method: 'client.applications.generateContent', example: - 'curl https://api.writer.com/v1/applications/$APPLICATION_ID \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "inputs": [\n {\n "id": "id",\n "value": [\n "string"\n ]\n }\n ]\n }\'', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGenerateContentResponse = await client.applications.generateContent(\n '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n { inputs: [{ id: 'id', value: ['string'] }] },\n);\n\nconsole.log(applicationGenerateContentResponse.suggestion);", }, python: { method: 'applications.generate_content', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfor application in client.applications.generate_content(\n application_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n inputs=[{\n "id": "id",\n "value": ["string"],\n }],\n):\n print(application)', }, - typescript: { - method: 'client.applications.generateContent', + go: { + method: 'client.Applications.GenerateContent', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGenerateContentResponse = await client.applications.generateContent(\n '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n { inputs: [{ id: 'id', value: ['string'] }] },\n);\n\nconsole.log(applicationGenerateContentResponse.suggestion);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGenerateContentResponse, err := client.Applications.GenerateContent(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\twritersdk.ApplicationGenerateContentParams{\n\t\t\tInputs: writersdk.F([]writersdk.ApplicationGenerateContentParamsInput{{\n\t\t\t\tID: writersdk.F("id"),\n\t\t\t\tValue: writersdk.F([]string{"string"}),\n\t\t\t}}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGenerateContentResponse.Suggestion)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/$APPLICATION_ID \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "inputs": [\n {\n "id": "id",\n "value": [\n "string"\n ]\n }\n ]\n }\'', }, }, }, @@ -106,24 +106,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## list\n\n`client.applications.list(after?: string, before?: string, limit?: number, order?: 'asc' | 'desc', type?: 'generation'): { id: string; created_at: string; inputs: object[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n\n**get** `/v1/applications`\n\nRetrieves a paginated list of no-code agents (formerly called no-code applications) with optional filtering and sorting capabilities.\n\n### Parameters\n\n- `after?: string`\n Return results after this application ID for pagination.\n\n- `before?: string`\n Return results before this application ID for pagination.\n\n- `limit?: number`\n Maximum number of applications to return in the response.\n\n- `order?: 'asc' | 'desc'`\n Sort order for the results based on creation time.\n\n- `type?: 'generation'`\n Filter applications by their type.\n\n### Returns\n\n- `{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n Detailed application object including its input configuration.\n\n - `id: string`\n - `created_at: string`\n - `inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]`\n - `name: string`\n - `status: 'deployed' | 'draft'`\n - `type: 'generation'`\n - `updated_at: string`\n - `last_deployed_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const applicationListResponse of client.applications.list()) {\n console.log(applicationListResponse);\n}\n```", perLanguage: { - go: { - method: 'client.Applications.List', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Applications.List(context.TODO(), writersdk.ApplicationListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', - }, - http: { + typescript: { + method: 'client.applications.list', example: - 'curl https://api.writer.com/v1/applications \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const applicationListResponse of client.applications.list()) {\n console.log(applicationListResponse.id);\n}", }, python: { method: 'applications.list', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\npage = client.applications.list()\npage = page.data[0]\nprint(page.id)', }, - typescript: { - method: 'client.applications.list', + go: { + method: 'client.Applications.List', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const applicationListResponse of client.applications.list()) {\n console.log(applicationListResponse.id);\n}", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Applications.List(context.TODO(), writersdk.ApplicationListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -142,24 +142,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## retrieve\n\n`client.applications.retrieve(application_id: string): { id: string; created_at: string; inputs: object[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n\n**get** `/v1/applications/{application_id}`\n\nRetrieves detailed information for a specific no-code agent (formerly called no-code applications), including its configuration and current status.\n\n### Parameters\n\n- `application_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n Detailed application object including its input configuration.\n\n - `id: string`\n - `created_at: string`\n - `inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]`\n - `name: string`\n - `status: 'deployed' | 'draft'`\n - `type: 'generation'`\n - `updated_at: string`\n - `last_deployed_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst application = await client.applications.retrieve('application_id');\n\nconsole.log(application);\n```", perLanguage: { - go: { - method: 'client.Applications.Get', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplication, err := client.Applications.Get(context.TODO(), "application_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", application.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.applications.retrieve', example: - 'curl https://api.writer.com/v1/applications/$APPLICATION_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst application = await client.applications.retrieve('application_id');\n\nconsole.log(application.id);", }, python: { method: 'applications.retrieve', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\napplication = client.applications.retrieve(\n "application_id",\n)\nprint(application.id)', }, - typescript: { - method: 'client.applications.retrieve', + go: { + method: 'client.Applications.Get', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst application = await client.applications.retrieve('application_id');\n\nconsole.log(application.id);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplication, err := client.Applications.Get(context.TODO(), "application_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", application.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/$APPLICATION_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -183,24 +183,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## list\n\n`client.applications.jobs.list(application_id: string, limit?: number, offset?: number, status?: 'in_progress' | 'failed' | 'completed'): { id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: application_generate_content_response; error?: string; updated_at?: string; }`\n\n**get** `/v1/applications/{application_id}/jobs`\n\nRetrieve all jobs created via the async API, linked to the provided application ID (or alias).\n\n### Parameters\n\n- `application_id: string`\n\n- `limit?: number`\n The pagination limit for retrieving the jobs.\n\n- `offset?: number`\n The pagination offset for retrieving the jobs.\n\n- `status?: 'in_progress' | 'failed' | 'completed'`\n The status of the job.\n\n### Returns\n\n- `{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }`\n\n - `id: string`\n - `application_id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n - `completed_at?: string`\n - `data?: { suggestion: string; title?: string; }`\n - `error?: string`\n - `updated_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const applicationGenerateAsyncResponse of client.applications.jobs.list('application_id')) {\n console.log(applicationGenerateAsyncResponse);\n}\n```", perLanguage: { - go: { - method: 'client.Applications.Jobs.List', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Applications.Jobs.List(\n\t\tcontext.TODO(),\n\t\t"application_id",\n\t\twritersdk.ApplicationJobListParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', - }, - http: { + typescript: { + method: 'client.applications.jobs.list', example: - 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/jobs \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const applicationGenerateAsyncResponse of client.applications.jobs.list(\n 'application_id',\n)) {\n console.log(applicationGenerateAsyncResponse.id);\n}", }, python: { method: 'applications.jobs.list', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\npage = client.applications.jobs.list(\n application_id="application_id",\n)\npage = page.result[0]\nprint(page.id)', }, - typescript: { - method: 'client.applications.jobs.list', + go: { + method: 'client.Applications.Jobs.List', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const applicationGenerateAsyncResponse of client.applications.jobs.list(\n 'application_id',\n)) {\n console.log(applicationGenerateAsyncResponse.id);\n}", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Applications.Jobs.List(\n\t\tcontext.TODO(),\n\t\t"application_id",\n\t\twritersdk.ApplicationJobListParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/jobs \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -218,24 +218,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## create\n\n`client.applications.jobs.create(application_id: string, inputs: { id: string; value: string[]; }[]): { id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n**post** `/v1/applications/{application_id}/jobs`\n\nGenerate content asynchronously from an existing no-code agent (formerly called no-code applications) with inputs.\n\n### Parameters\n\n- `application_id: string`\n\n- `inputs: { id: string; value: string[]; }[]`\n A list of input objects to generate content for.\n\n### Returns\n\n- `{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n - `id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst job = await client.applications.jobs.create('application_id', { inputs: [{ id: 'id', value: ['string'] }] });\n\nconsole.log(job);\n```", perLanguage: { - go: { - method: 'client.Applications.Jobs.New', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tjob, err := client.Applications.Jobs.New(\n\t\tcontext.TODO(),\n\t\t"application_id",\n\t\twritersdk.ApplicationJobNewParams{\n\t\t\tInputs: writersdk.F([]writersdk.ApplicationJobNewParamsInput{{\n\t\t\t\tID: writersdk.F("id"),\n\t\t\t\tValue: writersdk.F([]string{"string"}),\n\t\t\t}}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", job.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.applications.jobs.create', example: - 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/jobs \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "inputs": [\n {\n "id": "id",\n "value": [\n "string"\n ]\n }\n ]\n }\'', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst job = await client.applications.jobs.create('application_id', {\n inputs: [{ id: 'id', value: ['string'] }],\n});\n\nconsole.log(job.id);", }, python: { method: 'applications.jobs.create', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\njob = client.applications.jobs.create(\n application_id="application_id",\n inputs=[{\n "id": "id",\n "value": ["string"],\n }],\n)\nprint(job.id)', }, - typescript: { - method: 'client.applications.jobs.create', + go: { + method: 'client.Applications.Jobs.New', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst job = await client.applications.jobs.create('application_id', {\n inputs: [{ id: 'id', value: ['string'] }],\n});\n\nconsole.log(job.id);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tjob, err := client.Applications.Jobs.New(\n\t\tcontext.TODO(),\n\t\t"application_id",\n\t\twritersdk.ApplicationJobNewParams{\n\t\t\tInputs: writersdk.F([]writersdk.ApplicationJobNewParamsInput{{\n\t\t\t\tID: writersdk.F("id"),\n\t\t\t\tValue: writersdk.F([]string{"string"}),\n\t\t\t}}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", job.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/jobs \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "inputs": [\n {\n "id": "id",\n "value": [\n "string"\n ]\n }\n ]\n }\'', }, }, }, @@ -253,24 +253,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## retry\n\n`client.applications.jobs.retry(job_id: string): { id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n**post** `/v1/applications/jobs/{job_id}/retry`\n\nRe-triggers the async execution of a single job previously created via the Async api and terminated in error.\n\n### Parameters\n\n- `job_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n - `id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.applications.jobs.retry('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(response);\n```", perLanguage: { - go: { - method: 'client.Applications.Jobs.Retry', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Applications.Jobs.Retry(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.applications.jobs.retry', example: - 'curl https://api.writer.com/v1/applications/jobs/$JOB_ID/retry \\\n -X POST \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.applications.jobs.retry('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(response.id);", }, python: { method: 'applications.jobs.retry', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.applications.jobs.retry(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(response.id)', }, - typescript: { - method: 'client.applications.jobs.retry', + go: { + method: 'client.Applications.Jobs.Retry', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.applications.jobs.retry('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(response.id);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Applications.Jobs.Retry(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/jobs/$JOB_ID/retry \\\n -X POST \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -288,24 +288,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## retrieve\n\n`client.applications.jobs.retrieve(job_id: string): { id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: application_generate_content_response; error?: string; updated_at?: string; }`\n\n**get** `/v1/applications/jobs/{job_id}`\n\nRetrieves a single job created via the Async API.\n\n### Parameters\n\n- `job_id: string`\n\n### Returns\n\n- `{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }`\n\n - `id: string`\n - `application_id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n - `completed_at?: string`\n - `data?: { suggestion: string; title?: string; }`\n - `error?: string`\n - `updated_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGenerateAsyncResponse = await client.applications.jobs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(applicationGenerateAsyncResponse);\n```", perLanguage: { - go: { - method: 'client.Applications.Jobs.Get', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGenerateAsyncResponse, err := client.Applications.Jobs.Get(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGenerateAsyncResponse.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.applications.jobs.retrieve', example: - 'curl https://api.writer.com/v1/applications/jobs/$JOB_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGenerateAsyncResponse = await client.applications.jobs.retrieve(\n '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n);\n\nconsole.log(applicationGenerateAsyncResponse.id);", }, python: { method: 'applications.jobs.retrieve', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\napplication_generate_async_response = client.applications.jobs.retrieve(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(application_generate_async_response.id)', }, - typescript: { - method: 'client.applications.jobs.retrieve', + go: { + method: 'client.Applications.Jobs.Get', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGenerateAsyncResponse = await client.applications.jobs.retrieve(\n '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n);\n\nconsole.log(applicationGenerateAsyncResponse.id);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGenerateAsyncResponse, err := client.Applications.Jobs.Get(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGenerateAsyncResponse.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/jobs/$JOB_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -322,24 +322,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## list\n\n`client.applications.graphs.list(application_id: string): { graph_ids: string[]; }`\n\n**get** `/v1/applications/{application_id}/graphs`\n\nRetrieve Knowledge Graphs associated with a no-code agent that has chat capabilities.\n\n### Parameters\n\n- `application_id: string`\n\n### Returns\n\n- `{ graph_ids: string[]; }`\n\n - `graph_ids: string[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGraphsResponse = await client.applications.graphs.list('application_id');\n\nconsole.log(applicationGraphsResponse);\n```", perLanguage: { - go: { - method: 'client.Applications.Graphs.List', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGraphsResponse, err := client.Applications.Graphs.List(context.TODO(), "application_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGraphsResponse.GraphIDs)\n}\n', - }, - http: { + typescript: { + method: 'client.applications.graphs.list', example: - 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/graphs \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGraphsResponse = await client.applications.graphs.list('application_id');\n\nconsole.log(applicationGraphsResponse.graph_ids);", }, python: { method: 'applications.graphs.list', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\napplication_graphs_response = client.applications.graphs.list(\n "application_id",\n)\nprint(application_graphs_response.graph_ids)', }, - typescript: { - method: 'client.applications.graphs.list', + go: { + method: 'client.Applications.Graphs.List', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGraphsResponse = await client.applications.graphs.list('application_id');\n\nconsole.log(applicationGraphsResponse.graph_ids);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGraphsResponse, err := client.Applications.Graphs.List(context.TODO(), "application_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGraphsResponse.GraphIDs)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/graphs \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -356,24 +356,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## update\n\n`client.applications.graphs.update(application_id: string, graph_ids: string[]): { graph_ids: string[]; }`\n\n**put** `/v1/applications/{application_id}/graphs`\n\nUpdates the list of Knowledge Graphs associated with a no-code chat agent.\n\n### Parameters\n\n- `application_id: string`\n\n- `graph_ids: string[]`\n A list of Knowledge Graph IDs to associate with the application. Note that this will replace the existing list of Knowledge Graphs associated with the application, not add to it.\n\n### Returns\n\n- `{ graph_ids: string[]; }`\n\n - `graph_ids: string[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGraphsResponse = await client.applications.graphs.update('application_id', { graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(applicationGraphsResponse);\n```", perLanguage: { - go: { - method: 'client.Applications.Graphs.Update', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGraphsResponse, err := client.Applications.Graphs.Update(\n\t\tcontext.TODO(),\n\t\t"application_id",\n\t\twritersdk.ApplicationGraphUpdateParams{\n\t\t\tGraphIDs: writersdk.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGraphsResponse.GraphIDs)\n}\n', - }, - http: { + typescript: { + method: 'client.applications.graphs.update', example: - 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/graphs \\\n -X PUT \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "graph_ids": [\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"\n ]\n }\'', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGraphsResponse = await client.applications.graphs.update('application_id', {\n graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'],\n});\n\nconsole.log(applicationGraphsResponse.graph_ids);", }, python: { method: 'applications.graphs.update', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\napplication_graphs_response = client.applications.graphs.update(\n application_id="application_id",\n graph_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],\n)\nprint(application_graphs_response.graph_ids)', }, - typescript: { - method: 'client.applications.graphs.update', + go: { + method: 'client.Applications.Graphs.Update', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGraphsResponse = await client.applications.graphs.update('application_id', {\n graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'],\n});\n\nconsole.log(applicationGraphsResponse.graph_ids);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGraphsResponse, err := client.Applications.Graphs.Update(\n\t\tcontext.TODO(),\n\t\t"application_id",\n\t\twritersdk.ApplicationGraphUpdateParams{\n\t\t\tGraphIDs: writersdk.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGraphsResponse.GraphIDs)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/graphs \\\n -X PUT \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "graph_ids": [\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"\n ]\n }\'', }, }, }, @@ -406,24 +406,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## chat\n\n`client.chat.chat(messages: { role: 'user' | 'assistant' | 'system' | 'tool'; content?: string | { text: string; type: 'text'; } | { image_url: object; type: 'image_url'; }[]; graph_data?: object; name?: string; refusal?: string; tool_call_id?: string; tool_calls?: object[]; }[], model: string, logprobs?: boolean, max_tokens?: number, n?: number, response_format?: { type: 'text' | 'json_schema'; json_schema?: object; }, stop?: string[] | string, stream?: boolean, stream_options?: { include_usage: boolean; }, temperature?: number, tool_choice?: { value: 'none' | 'auto' | 'required'; } | { value: object; }, tools?: { function: function_definition; type: 'function'; } | { function: object; type: 'graph'; } | { function: object; type: 'llm'; } | { function: object; type: 'translation'; } | { function: object; type: 'vision'; } | { function: object; type: 'web_search'; }[], top_p?: number): { id: string; choices: chat_completion_choice[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: chat_completion_usage; }`\n\n**post** `/v1/chat`\n\nGenerate a chat completion based on the provided messages. The response shown below is for non-streaming. To learn about streaming responses, see the [chat completion guide](https://dev.writer.com/home/chat-completion).\n\n### Parameters\n\n- `messages: { role: 'user' | 'assistant' | 'system' | 'tool'; content?: string | { text: string; type: 'text'; } | { image_url: { url: string; }; type: 'image_url'; }[]; graph_data?: { references?: { files?: object[]; web?: object[]; }; sources?: object[]; status?: 'processing' | 'finished'; subqueries?: { answer: string; query: string; sources: source[]; }[]; }; name?: string; refusal?: string; tool_call_id?: string; tool_calls?: { id: string; function: { arguments: string; name?: string; }; type: 'function'; index?: number; }[]; }[]`\n An array of message objects that form the conversation history or context for the model to respond to. The array must contain at least one message.\n\n- `model: string`\n The [ID of the model](https://dev.writer.com/home/models) to use for creating the chat completion. Supports `palmyra-x5`, `palmyra-x4`, `palmyra-fin`, `palmyra-med`, `palmyra-creative`, and `palmyra-x-003-instruct`.\n\n- `logprobs?: boolean`\n Specifies whether to return log probabilities of the output tokens.\n\n- `max_tokens?: number`\n Defines the maximum number of tokens (words and characters) that the model can generate in the response. This can be adjusted to allow for longer or shorter responses as needed. The maximum value varies by model. See the [models overview](/home/models) for more information about the maximum number of tokens for each model.\n\n- `n?: number`\n Specifies the number of completions (responses) to generate from the model in a single request. This parameter allows for generating multiple responses, offering a variety of potential replies from which to choose.\n\n- `response_format?: { type: 'text' | 'json_schema'; json_schema?: object; }`\n The response format to use for the chat completion, available with `palmyra-x4` and `palmyra-x5`.\n\n`text` is the default response format. [JSON Schema](https://json-schema.org/) is supported for structured responses. If you specify `json_schema`, you must also provide a `json_schema` object.\n - `type: 'text' | 'json_schema'`\n The type of response format to use.\n - `json_schema?: object`\n The JSON schema to use for the response format.\n\n- `stop?: string[] | string`\n A token or sequence of tokens that, when generated, will cause the model to stop producing further content. This can be a single token or an array of tokens, acting as a signal to end the output.\n\n- `stream?: boolean`\n Indicates whether the response should be streamed incrementally as it is generated or only returned once fully complete. Streaming can be useful for providing real-time feedback in interactive applications.\n\n- `stream_options?: { include_usage: boolean; }`\n Additional options for streaming.\n - `include_usage: boolean`\n Indicate whether to include usage information.\n\n- `temperature?: number`\n Controls the randomness or creativity of the model's responses. A higher temperature results in more varied and less predictable text, while a lower temperature produces more deterministic and conservative outputs.\n\n- `tool_choice?: { value: 'none' | 'auto' | 'required'; } | { value: object; }`\n Configure how the model will call functions:\n- `auto`: allows the model to automatically choose the tool to use, or not call a tool\n- `none`: disables tool calling; the model will instead generate a message\n- `required`: requires the model to call one or more tools\n\nYou can also use a JSON object to force the model to call a specific tool. For example, `{\"type\": \"function\", \"function\": {\"name\": \"get_current_weather\"}}` requires the model to call the `get_current_weather` function, regardless of the prompt.\n\n- `tools?: { function: { name: string; description?: string; parameters?: function_params; }; type: 'function'; } | { function: { graph_ids: string[]; subqueries: boolean; description?: string; query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }; }; type: 'graph'; } | { function: { description: string; model: string; }; type: 'llm'; } | { function: { formality: boolean; length_control: boolean; mask_profanity: boolean; model: 'palmyra-translate'; source_language_code?: string; target_language_code?: string; }; type: 'translation'; } | { function: { model: 'palmyra-vision'; variables: { file_id: string; name: string; }[]; }; type: 'vision'; } | { function: { exclude_domains: string[]; include_domains: string[]; }; type: 'web_search'; }[]`\n An array containing tool definitions for tools that the model can use to generate responses. The tool definitions use JSON schema. You can define your own functions or use one of the built-in `graph`, `llm`, `translation`, or `vision` tools. Note that you can only use one built-in tool type in the array (only one of `graph`, `llm`, `translation`, or `vision`). You can pass multiple [custom tools](https://dev.writer.com/home/tool-calling) of type `function` in the same request.\n\n- `top_p?: number`\n Sets the threshold for \"nucleus sampling,\" a technique to focus the model's token generation on the most likely subset of tokens. Only tokens with cumulative probability above this threshold are considered, controlling the trade-off between creativity and coherence.\n\n### Returns\n\n- `{ id: string; choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: chat_completion_message; logprobs?: logprobs; }[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: object; prompt_token_details?: object; }; }`\n\n - `id: string`\n - `choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: { content: string; refusal: string; role: 'assistant'; graph_data?: graph_data; llm_data?: object; tool_calls?: tool_call[]; translation_data?: object; web_search_data?: object; }; logprobs?: { content: logprobs_token[]; refusal: logprobs_token[]; }; }[]`\n - `created: number`\n - `model: string`\n - `object: 'chat.completion'`\n - `service_tier?: string`\n - `system_fingerprint?: string`\n - `usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: { reasoning_tokens: number; }; prompt_token_details?: { cached_tokens: number; }; }`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.chat.chat({ messages: [{ role: 'user' }], model: 'model' });\nfor await (const chatCompletionChunk of stream) {\n console.log(chatCompletionChunk);\n}\n```", perLanguage: { - go: { - method: 'client.Chat.Chat', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tchatCompletion, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("model"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chatCompletion.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.chat.chat', example: - 'curl https://api.writer.com/v1/chat \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "messages": [\n {\n "role": "user"\n }\n ],\n "model": "model"\n }\'', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst chatCompletion = await client.chat.chat({ messages: [{ role: 'user' }], model: 'model' });\n\nconsole.log(chatCompletion.id);", }, python: { method: 'chat.chat', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfor chat in client.chat.chat(\n messages=[{\n "role": "user"\n }],\n model="model",\n):\n print(chat)', }, - typescript: { - method: 'client.chat.chat', + go: { + method: 'client.Chat.Chat', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst chatCompletion = await client.chat.chat({ messages: [{ role: 'user' }], model: 'model' });\n\nconsole.log(chatCompletion.id);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tchatCompletion, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("model"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chatCompletion.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/chat \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "messages": [\n {\n "role": "user"\n }\n ],\n "model": "model"\n }\'', }, }, }, @@ -451,24 +451,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## create\n\n`client.completions.create(model: string, prompt: string, best_of?: number, max_tokens?: number, random_seed?: number, stop?: string[] | string, stream?: boolean, temperature?: number, top_p?: number): { choices: object[]; model?: string; }`\n\n**post** `/v1/completions`\n\nGenerate text completions using the specified model and prompt. This endpoint is useful for text generation tasks that don't require conversational context.\n\n### Parameters\n\n- `model: string`\n The [ID of the model](https://dev.writer.com/home/models) to use for generating text. Supports `palmyra-x5`, `palmyra-x4`, `palmyra-fin`, `palmyra-med`, `palmyra-creative`, and `palmyra-x-003-instruct`.\n\n- `prompt: string`\n The input text that the model will process to generate a response.\n\n- `best_of?: number`\n Specifies the number of completions to generate and return the best one. Useful for generating multiple outputs and choosing the best based on some criteria.\n\n- `max_tokens?: number`\n The maximum number of tokens that the model can generate in the response.\n\n- `random_seed?: number`\n A seed used to initialize the random number generator for the model, ensuring reproducibility of the output when the same inputs are provided.\n\n- `stop?: string[] | string`\n Specifies stopping conditions for the model's output generation. This can be an array of strings or a single string that the model will look for as a signal to stop generating further tokens.\n\n- `stream?: boolean`\n Determines whether the model's output should be streamed. If true, the output is generated and sent incrementally, which can be useful for real-time applications.\n\n- `temperature?: number`\n Controls the randomness of the model's outputs. Higher values lead to more random outputs, while lower values make the model more deterministic.\n\n- `top_p?: number`\n Used to control the nucleus sampling, where only the most probable tokens with a cumulative probability of top_p are considered for sampling, providing a way to fine-tune the randomness of predictions.\n\n### Returns\n\n- `{ choices: { text: string; log_probs?: object; }[]; model?: string; }`\n\n - `choices: { text: string; log_probs?: { content: object[]; refusal: object[]; }; }[]`\n - `model?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.completions.create({ model: 'palmyra-x-003-instruct', prompt: 'Write me an SEO article about...' });\nfor await (const completionChunk of stream) {\n console.log(completionChunk);\n}\n```", perLanguage: { - go: { - method: 'client.Completions.New', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tcompletion, err := client.Completions.New(context.TODO(), writersdk.CompletionNewParams{\n\t\tModel: writersdk.F("palmyra-x-003-instruct"),\n\t\tPrompt: writersdk.F("Write me an SEO article about..."),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", completion.Choices)\n}\n', - }, - http: { + typescript: { + method: 'client.completions.create', example: - 'curl https://api.writer.com/v1/completions \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "model": "palmyra-x-003-instruct",\n "prompt": "Write me an SEO article about..."\n }\'', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst completion = await client.completions.create({\n model: 'palmyra-x-003-instruct',\n prompt: 'Write me an SEO article about...',\n});\n\nconsole.log(completion.choices);", }, python: { method: 'completions.create', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfor completion in client.completions.create(\n model="palmyra-x-003-instruct",\n prompt="Write me an SEO article about...",\n):\n print(completion)', }, - typescript: { - method: 'client.completions.create', + go: { + method: 'client.Completions.New', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst completion = await client.completions.create({\n model: 'palmyra-x-003-instruct',\n prompt: 'Write me an SEO article about...',\n});\n\nconsole.log(completion.choices);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tcompletion, err := client.Completions.New(context.TODO(), writersdk.CompletionNewParams{\n\t\tModel: writersdk.F("palmyra-x-003-instruct"),\n\t\tPrompt: writersdk.F("Write me an SEO article about..."),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", completion.Choices)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/completions \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "model": "palmyra-x-003-instruct",\n "prompt": "Write me an SEO article about..."\n }\'', }, }, }, @@ -485,23 +485,23 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## list\n\n`client.models.list(): { models: object[]; }`\n\n**get** `/v1/models`\n\nRetrieve a list of available models that can be used for text generation, chat completions, and other AI tasks.\n\n### Returns\n\n- `{ models: { id: string; name: string; }[]; }`\n\n - `models: { id: string; name: string; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst models = await client.models.list();\n\nconsole.log(models);\n```", perLanguage: { - go: { - method: 'client.Models.List', + typescript: { + method: 'client.models.list', example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tmodels, err := client.Models.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", models.Models)\n}\n', - }, - http: { - example: 'curl https://api.writer.com/v1/models \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst models = await client.models.list();\n\nconsole.log(models.models);", }, python: { method: 'models.list', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nmodels = client.models.list()\nprint(models.models)', }, - typescript: { - method: 'client.models.list', + go: { + method: 'client.Models.List', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst models = await client.models.list();\n\nconsole.log(models.models);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tmodels, err := client.Models.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", models.Models)\n}\n', + }, + http: { + example: 'curl https://api.writer.com/v1/models \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -519,23 +519,23 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## list\n\n`client.graphs.list(after?: string, before?: string, limit?: number, order?: 'asc' | 'desc'): { id: string; created_at: string; file_status: object; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: object[]; }`\n\n**get** `/v1/graphs`\n\nRetrieve a list of Knowledge Graphs.\n\n### Parameters\n\n- `after?: string`\n The ID of the last object in the previous page. This parameter instructs the API to return the next page of results.\n\n- `before?: string`\n The ID of the first object in the previous page. This parameter instructs the API to return the previous page of results.\n\n- `limit?: number`\n Specifies the maximum number of objects returned in a page. The default value is 50. The minimum value is 1, and the maximum value is 100.\n\n- `order?: 'asc' | 'desc'`\n Specifies the order of the results. Valid values are asc for ascending and desc for descending.\n\n### Returns\n\n- `{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `file_status: { completed: number; failed: number; in_progress: number; total: number; }`\n - `name: string`\n - `type: 'manual' | 'connector' | 'web'`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const graph of client.graphs.list()) {\n console.log(graph);\n}\n```", perLanguage: { - go: { - method: 'client.Graphs.List', + typescript: { + method: 'client.graphs.list', example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Graphs.List(context.TODO(), writersdk.GraphListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', - }, - http: { - example: 'curl https://api.writer.com/v1/graphs \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const graph of client.graphs.list()) {\n console.log(graph.id);\n}", }, python: { method: 'graphs.list', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\npage = client.graphs.list()\npage = page.data[0]\nprint(page.id)', }, - typescript: { - method: 'client.graphs.list', + go: { + method: 'client.Graphs.List', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const graph of client.graphs.list()) {\n console.log(graph.id);\n}", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Graphs.List(context.TODO(), writersdk.GraphListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', + }, + http: { + example: 'curl https://api.writer.com/v1/graphs \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -553,24 +553,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## create\n\n`client.graphs.create(description?: string, name?: string): { id: string; created_at: string; name: string; description?: string; urls?: object[]; }`\n\n**post** `/v1/graphs`\n\nCreate a new Knowledge Graph.\n\n### Parameters\n\n- `description?: string`\n A description of the Knowledge Graph (max 255 characters). Omitting this field leaves the description unchanged.\n\n- `name?: string`\n The name of the Knowledge Graph (max 255 characters). Omitting this field leaves the name unchanged.\n\n### Returns\n\n- `{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `name: string`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.create();\n\nconsole.log(graph);\n```", perLanguage: { - go: { - method: 'client.Graphs.New', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.New(context.TODO(), writersdk.GraphNewParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.graphs.create', example: - "curl https://api.writer.com/v1/graphs \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'", + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.create();\n\nconsole.log(graph.id);", }, python: { method: 'graphs.create', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ngraph = client.graphs.create()\nprint(graph.id)', }, - typescript: { - method: 'client.graphs.create', + go: { + method: 'client.Graphs.New', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.create();\n\nconsole.log(graph.id);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.New(context.TODO(), writersdk.GraphNewParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', + }, + http: { + example: + "curl https://api.writer.com/v1/graphs \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'", }, }, }, @@ -588,24 +588,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## retrieve\n\n`client.graphs.retrieve(graph_id: string): { id: string; created_at: string; file_status: object; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: object[]; }`\n\n**get** `/v1/graphs/{graph_id}`\n\nRetrieve a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `file_status: { completed: number; failed: number; in_progress: number; total: number; }`\n - `name: string`\n - `type: 'manual' | 'connector' | 'web'`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", perLanguage: { - go: { - method: 'client.Graphs.Get', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.Get(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.graphs.retrieve', example: - 'curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);", }, python: { method: 'graphs.retrieve', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ngraph = client.graphs.retrieve(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(graph.id)', }, - typescript: { - method: 'client.graphs.retrieve', + go: { + method: 'client.Graphs.Get', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.Get(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -628,24 +628,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## update\n\n`client.graphs.update(graph_id: string, description?: string, name?: string, urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]): { id: string; created_at: string; name: string; description?: string; urls?: object[]; }`\n\n**put** `/v1/graphs/{graph_id}`\n\nUpdate the name and description of a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `description?: string`\n A description of the Knowledge Graph (max 255 characters). Omitting this field leaves the description unchanged.\n\n- `name?: string`\n The name of the Knowledge Graph (max 255 characters). Omitting this field leaves the name unchanged.\n\n- `urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n An array of web connector URLs to update for this Knowledge Graph. You can only connect URLs to Knowledge Graphs with the type `web`. To clear the list of URLs, set this field to an empty array.\n\n### Returns\n\n- `{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `name: string`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.update('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", perLanguage: { - go: { - method: 'client.Graphs.Update', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.Update(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\twritersdk.GraphUpdateParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.graphs.update', example: - "curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -X PUT \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'", + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.update('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);", }, python: { method: 'graphs.update', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ngraph = client.graphs.update(\n graph_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(graph.id)', }, - typescript: { - method: 'client.graphs.update', + go: { + method: 'client.Graphs.Update', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.update('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.Update(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\twritersdk.GraphUpdateParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', + }, + http: { + example: + "curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -X PUT \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'", }, }, }, @@ -662,24 +662,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## delete\n\n`client.graphs.delete(graph_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/graphs/{graph_id}`\n\nDelete a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.delete('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", perLanguage: { - go: { - method: 'client.Graphs.Delete', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.Delete(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.graphs.delete', example: - 'curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -X DELETE \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.delete('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);", }, python: { method: 'graphs.delete', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ngraph = client.graphs.delete(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(graph.id)', }, - typescript: { - method: 'client.graphs.delete', + go: { + method: 'client.Graphs.Delete', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.delete('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.Delete(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -X DELETE \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -696,24 +696,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## add_file_to_graph\n\n`client.graphs.addFileToGraph(graph_id: string, file_id: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**post** `/v1/graphs/{graph_id}/file`\n\nAdd a file to a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `file_id: string`\n The unique identifier of the file.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { file_id: 'file_id' });\n\nconsole.log(file);\n```", perLanguage: { - go: { - method: 'client.Graphs.AddFileToGraph', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Graphs.AddFileToGraph(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\twritersdk.GraphAddFileToGraphParams{\n\t\t\tFileID: writersdk.F("file_id"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.graphs.addFileToGraph', example: - 'curl https://api.writer.com/v1/graphs/$GRAPH_ID/file \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "file_id": "file_id"\n }\'', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', {\n file_id: 'file_id',\n});\n\nconsole.log(file.id);", }, python: { method: 'graphs.add_file_to_graph', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfile = client.graphs.add_file_to_graph(\n graph_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n file_id="file_id",\n)\nprint(file.id)', }, - typescript: { - method: 'client.graphs.addFileToGraph', + go: { + method: 'client.Graphs.AddFileToGraph', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', {\n file_id: 'file_id',\n});\n\nconsole.log(file.id);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Graphs.AddFileToGraph(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\twritersdk.GraphAddFileToGraphParams{\n\t\t\tFileID: writersdk.F("file_id"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/graphs/$GRAPH_ID/file \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "file_id": "file_id"\n }\'', }, }, }, @@ -730,24 +730,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## remove_file_from_graph\n\n`client.graphs.removeFileFromGraph(graph_id: string, file_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/graphs/{graph_id}/file/{file_id}`\n\nRemove a file from a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.graphs.removeFileFromGraph('file_id', { graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e' });\n\nconsole.log(response);\n```", perLanguage: { - go: { - method: 'client.Graphs.RemoveFileFromGraph', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Graphs.RemoveFileFromGraph(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\t"file_id",\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.graphs.removeFileFromGraph', example: - 'curl https://api.writer.com/v1/graphs/$GRAPH_ID/file/$FILE_ID \\\n -X DELETE \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.graphs.removeFileFromGraph('file_id', {\n graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n});\n\nconsole.log(response.id);", }, python: { method: 'graphs.remove_file_from_graph', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.graphs.remove_file_from_graph(\n file_id="file_id",\n graph_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(response.id)', }, - typescript: { - method: 'client.graphs.removeFileFromGraph', + go: { + method: 'client.Graphs.RemoveFileFromGraph', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.graphs.removeFileFromGraph('file_id', {\n graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n});\n\nconsole.log(response.id);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Graphs.RemoveFileFromGraph(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\t"file_id",\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/graphs/$GRAPH_ID/file/$FILE_ID \\\n -X DELETE \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -771,24 +771,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## question\n\n`client.graphs.question(graph_ids: string[], question: string, query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }, stream?: boolean, subqueries?: boolean): { answer: string; question: string; sources: source[]; references?: object; subqueries?: object[]; }`\n\n**post** `/v1/graphs/question`\n\nAsk a question to specified Knowledge Graphs.\n\n### Parameters\n\n- `graph_ids: string[]`\n The unique identifiers of the Knowledge Graphs to query.\n\n- `question: string`\n The question to answer using the Knowledge Graph.\n\n- `query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }`\n Configuration options for Knowledge Graph queries, including search parameters and citation settings.\n - `grounding_level?: number`\n Level of grounding required for responses, controlling how closely answers must be tied to source material. Set lower for grounded outputs, higher for creativity. Higher values (closer to 1.0) allow more creative interpretation, while lower values (closer to 0.0) stick more closely to source material. Range: 0.0-1.0, Default: 0.0.\n - `inline_citations?: boolean`\n Whether to include inline citations in the response, showing which Knowledge Graph sources were used. Default: false.\n - `keyword_threshold?: number`\n Threshold for keyword-based matching when searching Knowledge Graph content. Set higher for stricter relevance, lower for broader range. Higher values (closer to 1.0) require stronger keyword matches, while lower values (closer to 0.0) allow more lenient matching. Range: 0.0-1.0, Default: 0.7.\n - `max_snippets?: number`\n Maximum number of text snippets to retrieve from the Knowledge Graph for context. Works in concert with `search_weight` to control best matches vs broader coverage. While technically supports 1-60, values below 5 may return no results due to RAG implementation. Recommended range: 5-25. Due to RAG system behavior, you may see more snippets than requested. Range: 1-60, Default: 30.\n - `max_subquestions?: number`\n Maximum number of subquestions to generate when processing complex queries. Set higher to improve detail, set lower to reduce response time. Range: 1-10, Default: 6.\n - `max_tokens?: number`\n Maximum number of tokens the model can generate in the response. This controls the length of the AI's answer. Set higher for longer answers, set lower for shorter, faster answers. Range: 100-8000, Default: 4000.\n - `search_weight?: number`\n Weight given to search results when ranking and selecting relevant information. Higher values (closer to 100) prioritize keyword-based matching, while lower values (closer to 0) prioritize semantic similarity matching. Use higher values for exact keyword searches, lower values for conceptual similarity searches. Range: 0-100, Default: 50.\n - `semantic_threshold?: number`\n Threshold for semantic similarity matching when searching Knowledge Graph content. Set higher for stricter relevance, lower for broader range. Higher values (closer to 1.0) require stronger semantic similarity, while lower values (closer to 0.0) allow more lenient semantic matching. Range: 0.0-1.0, Default: 0.7.\n\n- `stream?: boolean`\n Determines whether the model's output should be streamed. If true, the output is generated and sent incrementally, which can be useful for real-time applications.\n\n- `subqueries?: boolean`\n Specify whether to include subqueries.\n\n### Returns\n\n- `{ answer: string; question: string; sources: { file_id: string; snippet: string; }[]; references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }; subqueries?: { answer: string; query: string; sources: object[]; }[]; }`\n\n - `answer: string`\n - `question: string`\n - `sources: { file_id: string; snippet: string; }[]`\n - `references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }`\n - `subqueries?: { answer: string; query: string; sources: { file_id: string; snippet: string; }[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.graphs.question({ graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], question: 'question' });\nfor await (const questionResponseChunk of stream) {\n console.log(questionResponseChunk);\n}\n```", perLanguage: { - go: { - method: 'client.Graphs.Question', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tquestion, err := client.Graphs.Question(context.TODO(), writersdk.GraphQuestionParams{\n\t\tGraphIDs: writersdk.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}),\n\t\tQuestion: writersdk.F("question"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", question.Answer)\n}\n', - }, - http: { + typescript: { + method: 'client.graphs.question', example: - 'curl https://api.writer.com/v1/graphs/question \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "graph_ids": [\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"\n ],\n "question": "question"\n }\'', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst question = await client.graphs.question({\n graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'],\n question: 'question',\n});\n\nconsole.log(question.answer);", }, python: { method: 'graphs.question', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfor graph in client.graphs.question(\n graph_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],\n question="question",\n):\n print(graph)', }, - typescript: { - method: 'client.graphs.question', + go: { + method: 'client.Graphs.Question', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst question = await client.graphs.question({\n graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'],\n question: 'question',\n});\n\nconsole.log(question.answer);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tquestion, err := client.Graphs.Question(context.TODO(), writersdk.GraphQuestionParams{\n\t\tGraphIDs: writersdk.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}),\n\t\tQuestion: writersdk.F("question"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", question.Answer)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/graphs/question \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "graph_ids": [\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"\n ],\n "question": "question"\n }\'', }, }, }, @@ -806,24 +806,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## retrieve\n\n`client.files.retrieve(file_id: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**get** `/v1/files/{file_id}`\n\nRetrieve detailed information about a specific file, including its metadata, status, and associated graphs.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.retrieve('file_id');\n\nconsole.log(file);\n```", perLanguage: { - go: { - method: 'client.Files.Get', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Get(context.TODO(), "file_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.files.retrieve', example: - 'curl https://api.writer.com/v1/files/$FILE_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.retrieve('file_id');\n\nconsole.log(file.id);", }, python: { method: 'files.retrieve', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfile = client.files.retrieve(\n "file_id",\n)\nprint(file.id)', }, - typescript: { - method: 'client.files.retrieve', + go: { + method: 'client.Files.Get', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.retrieve('file_id');\n\nconsole.log(file.id);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Get(context.TODO(), "file_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/files/$FILE_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -840,24 +840,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## delete\n\n`client.files.delete(file_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/files/{file_id}`\n\nPermanently delete a file from the system. This action cannot be undone.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.delete('file_id');\n\nconsole.log(file);\n```", perLanguage: { - go: { - method: 'client.Files.Delete', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Delete(context.TODO(), "file_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.files.delete', example: - 'curl https://api.writer.com/v1/files/$FILE_ID \\\n -X DELETE \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.delete('file_id');\n\nconsole.log(file.id);", }, python: { method: 'files.delete', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfile = client.files.delete(\n "file_id",\n)\nprint(file.id)', }, - typescript: { - method: 'client.files.delete', + go: { + method: 'client.Files.Delete', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.delete('file_id');\n\nconsole.log(file.id);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Delete(context.TODO(), "file_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/files/$FILE_ID \\\n -X DELETE \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -883,23 +883,23 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## list\n\n`client.files.list(after?: string, before?: string, file_types?: string, graph_id?: string, limit?: number, order?: 'asc' | 'desc', status?: 'in_progress' | 'completed' | 'failed'): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**get** `/v1/files`\n\nRetrieve a paginated list of files with optional filtering by status, graph association, and file type.\n\n### Parameters\n\n- `after?: string`\n The ID of the last object in the previous page. This parameter instructs the API to return the next page of results.\n\n- `before?: string`\n The ID of the first object in the previous page. This parameter instructs the API to return the previous page of results.\n\n- `file_types?: string`\n The extensions of the files to retrieve. Separate multiple extensions with a comma. For example: `pdf,jpg,docx`.\n\n- `graph_id?: string`\n The unique identifier of the graph to which the files belong.\n\n- `limit?: number`\n Specifies the maximum number of objects returned in a page. The default value is 50. The minimum value is 1, and the maximum value is 100.\n\n- `order?: 'asc' | 'desc'`\n Specifies the order of the results. Valid values are asc for ascending and desc for descending.\n\n- `status?: 'in_progress' | 'completed' | 'failed'`\n Specifies the status of the files to retrieve. Valid values are in_progress, completed or failed.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const file of client.files.list()) {\n console.log(file);\n}\n```", perLanguage: { - go: { - method: 'client.Files.List', + typescript: { + method: 'client.files.list', example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Files.List(context.TODO(), writersdk.FileListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', - }, - http: { - example: 'curl https://api.writer.com/v1/files \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const file of client.files.list()) {\n console.log(file.id);\n}", }, python: { method: 'files.list', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\npage = client.files.list()\npage = page.data[0]\nprint(page.id)', }, - typescript: { - method: 'client.files.list', + go: { + method: 'client.Files.List', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const file of client.files.list()) {\n console.log(file.id);\n}", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Files.List(context.TODO(), writersdk.FileListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', + }, + http: { + example: 'curl https://api.writer.com/v1/files \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -917,24 +917,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## upload\n\n`client.files.upload(content: string, Content-Disposition: string, graphId?: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**post** `/v1/files`\n\nUpload a new file to the system. Supports various file formats including PDF, DOC, DOCX, PPT, PPTX, JPG, PNG, EML, HTML, SRT, CSV, XLS, and XLSX.\n\n### Parameters\n\n- `content: string`\n\n- `Content-Disposition: string`\n\n- `graphId?: string`\n The unique identifier of the Knowledge Graph to associate the uploaded file with.\n\nNote: The response from the upload endpoint does not include the `graphId` field, but the association will be visible when you retrieve the file using the file retrieval endpoint.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.upload({ content: fs.createReadStream('path/to/file'), 'Content-Disposition': 'Content-Disposition' });\n\nconsole.log(file);\n```", perLanguage: { - go: { - method: 'client.Files.Upload', - example: - 'package main\n\nimport (\n\t"bytes"\n\t"context"\n\t"fmt"\n\t"io"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Upload(context.TODO(), writersdk.FileUploadParams{\n\t\tContent: io.Reader(bytes.NewBuffer([]byte("Example data"))),\n\t\tContentDisposition: writersdk.F("Content-Disposition"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', - }, - http: { + typescript: { + method: 'client.files.upload', example: - "curl https://api.writer.com/v1/files \\\n -H 'Content-Type: text/plain' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -F 'content=@/path/to/content'", + "import fs from 'fs';\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.upload({\n content: fs.createReadStream('path/to/file'),\n 'Content-Disposition': 'Content-Disposition',\n});\n\nconsole.log(file.id);", }, python: { method: 'files.upload', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfile = client.files.upload(\n content=b"Example data",\n content_disposition="Content-Disposition",\n)\nprint(file.id)', }, - typescript: { - method: 'client.files.upload', + go: { + method: 'client.Files.Upload', example: - "import fs from 'fs';\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.upload({\n content: fs.createReadStream('path/to/file'),\n 'Content-Disposition': 'Content-Disposition',\n});\n\nconsole.log(file.id);", + 'package main\n\nimport (\n\t"bytes"\n\t"context"\n\t"fmt"\n\t"io"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Upload(context.TODO(), writersdk.FileUploadParams{\n\t\tContent: io.Reader(bytes.NewBuffer([]byte("Example data"))),\n\t\tContentDisposition: writersdk.F("Content-Disposition"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', + }, + http: { + example: + "curl https://api.writer.com/v1/files \\\n -H 'Content-Type: text/plain' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -F 'content=@/path/to/content'", }, }, }, @@ -952,24 +952,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## download\n\n`client.files.download(file_id: string): string`\n\n**get** `/v1/files/{file_id}/download`\n\nDownload the binary content of a file. The response will contain the file data in the appropriate MIME type.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.files.download('file_id');\n\nconsole.log(response);\n\nconst content = await response.blob()\nconsole.log(content)\n```", perLanguage: { - go: { - method: 'client.Files.Download', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Files.Download(context.TODO(), "file_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response)\n}\n', - }, - http: { + typescript: { + method: 'client.files.download', example: - 'curl https://api.writer.com/v1/files/$FILE_ID/download \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.files.download('file_id');\n\nconsole.log(response);\n\nconst content = await response.blob();\nconsole.log(content);", }, python: { method: 'files.download', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.files.download(\n "file_id",\n)\nprint(response)\ncontent = response.read()\nprint(content)', }, - typescript: { - method: 'client.files.download', + go: { + method: 'client.Files.Download', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.files.download('file_id');\n\nconsole.log(response);\n\nconst content = await response.blob();\nconsole.log(content);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Files.Download(context.TODO(), "file_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/files/$FILE_ID/download \\\n -H "Authorization: Bearer $WRITER_API_KEY"', }, }, }, @@ -987,24 +987,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## retry\n\n`client.files.retry(file_ids: string[]): { success?: boolean; }`\n\n**post** `/v1/files/retry`\n\nRetry processing of files that previously failed to process. This will re-attempt the processing of the specified files.\n\n### Parameters\n\n- `file_ids: string[]`\n The unique identifier of the files to retry.\n\n### Returns\n\n- `{ success?: boolean; }`\n\n - `success?: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.files.retry({ file_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(response);\n```", perLanguage: { - go: { - method: 'client.Files.Retry', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Files.Retry(context.TODO(), writersdk.FileRetryParams{\n\t\tFileIDs: writersdk.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Success)\n}\n', - }, - http: { + typescript: { + method: 'client.files.retry', example: - 'curl https://api.writer.com/v1/files/retry \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "file_ids": [\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"\n ]\n }\'', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.files.retry({ file_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(response.success);", }, python: { method: 'files.retry', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.files.retry(\n file_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],\n)\nprint(response.success)', }, - typescript: { - method: 'client.files.retry', + go: { + method: 'client.Files.Retry', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.files.retry({ file_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(response.success);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Files.Retry(context.TODO(), writersdk.FileRetryParams{\n\t\tFileIDs: writersdk.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Success)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/files/retry \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "file_ids": [\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"\n ]\n }\'', }, }, }, @@ -1021,24 +1021,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## parse_pdf\n\n`client.tools.parsePdf(file_id: string, format: 'text' | 'markdown'): { content: string; }`\n\n**post** `/v1/tools/pdf-parser/{file_id}`\n\nParse PDF to other formats.\n\n### Parameters\n\n- `file_id: string`\n\n- `format: 'text' | 'markdown'`\n The format into which the PDF content should be converted.\n\n### Returns\n\n- `{ content: string; }`\n\n - `content: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.tools.parsePdf('file_id', { format: 'text' });\n\nconsole.log(response);\n```", perLanguage: { - go: { - method: 'client.Tools.ParsePdf', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Tools.ParsePdf(\n\t\tcontext.TODO(),\n\t\t"file_id",\n\t\twritersdk.ToolParsePdfParams{\n\t\t\tFormat: writersdk.F(writersdk.ToolParsePdfParamsFormatText),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Content)\n}\n', - }, - http: { + typescript: { + method: 'client.tools.parsePdf', example: - 'curl https://api.writer.com/v1/tools/pdf-parser/$FILE_ID \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "format": "text"\n }\'', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.tools.parsePdf('file_id', { format: 'text' });\n\nconsole.log(response.content);", }, python: { method: 'tools.parse_pdf', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.tools.parse_pdf(\n file_id="file_id",\n format="text",\n)\nprint(response.content)', }, - typescript: { - method: 'client.tools.parsePdf', + go: { + method: 'client.Tools.ParsePdf', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.tools.parsePdf('file_id', { format: 'text' });\n\nconsole.log(response.content);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Tools.ParsePdf(\n\t\tcontext.TODO(),\n\t\t"file_id",\n\t\twritersdk.ToolParsePdfParams{\n\t\t\tFormat: writersdk.F(writersdk.ToolParsePdfParamsFormatText),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Content)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/tools/pdf-parser/$FILE_ID \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "format": "text"\n }\'', }, }, }, @@ -1070,24 +1070,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## web_search\n\n`client.tools.webSearch(chunks_per_source?: number, country?: string, days?: number, exclude_domains?: string[], include_answer?: boolean, include_domains?: string[], include_raw_content?: 'text' | 'markdown' | boolean, max_results?: number, query?: string, search_depth?: 'basic' | 'advanced', stream?: boolean, time_range?: 'day' | 'week' | 'month' | 'year' | 'd' | 'w' | 'm' | 'y', topic?: 'general' | 'news'): { query: string; sources: object[]; answer?: string; }`\n\n**post** `/v1/tools/web-search`\n\nSearch the web for information about a given query and return relevant results with source URLs.\n\n### Parameters\n\n- `chunks_per_source?: number`\n Only applies when `search_depth` is `advanced`. Specifies how many text segments to extract from each source. Limited to 3 chunks maximum.\n\n- `country?: string`\n Localizes search results to a specific country. Only applies to general topic searches.\n\n- `days?: number`\n For news topic searches, specifies how many days of news coverage to include.\n\n- `exclude_domains?: string[]`\n Domains to exclude from the search. If unset, the search includes all domains.\n\n- `include_answer?: boolean`\n Whether to include a generated answer to the query in the response. If `false`, only search results are returned.\n\n- `include_domains?: string[]`\n Domains to include in the search. If unset, the search includes all domains.\n\n- `include_raw_content?: 'text' | 'markdown' | boolean`\n Controls how raw content is included in search results:\n\n- `text`: Returns plain text without formatting markup\n- `markdown`: Returns structured content with markdown formatting (headers, links, bold text)\n- `true`: Same as `markdown`\n- `false`: Raw content is not included (default if unset)\n\n- `max_results?: number`\n Limits the number of search results returned. Cannot exceed 20 sources.\n\n- `query?: string`\n The search query.\n\n- `search_depth?: 'basic' | 'advanced'`\n Controls search comprehensiveness:\n\n- `basic`: Returns fewer but highly relevant results\n- `advanced`: Performs a deeper search with more results\n\n- `stream?: boolean`\n Enables streaming of search results as they become available.\n\n- `time_range?: 'day' | 'week' | 'month' | 'year' | 'd' | 'w' | 'm' | 'y'`\n Filters results to content published within the specified time range back from the current date. For example, `week` or `w` returns results from the past 7 days.\n\n- `topic?: 'general' | 'news'`\n The search topic category. Use `news` for current events and news articles, or `general` for broader web search.\n\n### Returns\n\n- `{ query: string; sources: { raw_content?: string; url?: string; }[]; answer?: string; }`\n\n - `query: string`\n - `sources: { raw_content?: string; url?: string; }[]`\n - `answer?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.tools.webSearch();\n\nconsole.log(response);\n```", perLanguage: { - go: { - method: 'client.Tools.WebSearch', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Tools.WebSearch(context.TODO(), writersdk.ToolWebSearchParams{\n\t\tIncludeDomains: writersdk.F([]string{"dev.writer.com"}),\n\t\tQuery: writersdk.F("How do I get an API key for the Writer API?"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Query)\n}\n', - }, - http: { + typescript: { + method: 'client.tools.webSearch', example: - "curl https://api.writer.com/v1/tools/web-search \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'", + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.tools.webSearch({\n include_domains: ['dev.writer.com'],\n query: 'How do I get an API key for the Writer API?',\n});\n\nconsole.log(response.query);", }, python: { method: 'tools.web_search', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.tools.web_search(\n include_domains=["dev.writer.com"],\n query="How do I get an API key for the Writer API?",\n)\nprint(response.query)', }, - typescript: { - method: 'client.tools.webSearch', + go: { + method: 'client.Tools.WebSearch', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.tools.webSearch({\n include_domains: ['dev.writer.com'],\n query: 'How do I get an API key for the Writer API?',\n});\n\nconsole.log(response.query);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Tools.WebSearch(context.TODO(), writersdk.ToolWebSearchParams{\n\t\tIncludeDomains: writersdk.F([]string{"dev.writer.com"}),\n\t\tQuery: writersdk.F("How do I get an API key for the Writer API?"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Query)\n}\n', + }, + http: { + example: + "curl https://api.writer.com/v1/tools/web-search \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'", }, }, }, @@ -1112,24 +1112,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## translate\n\n`client.translation.translate(formality: boolean, length_control: boolean, mask_profanity: boolean, model: 'palmyra-translate', source_language_code: string, target_language_code: string, text: string): { data: string; }`\n\n**post** `/v1/translation`\n\nTranslate text from one language to another.\n\n### Parameters\n\n- `formality: boolean`\n Whether to use formal or informal language in the translation. See the [list of languages that support formality](https://dev.writer.com/api-reference/translation-api/language-support#formality). If the language does not support formality, this parameter is ignored.\n\n- `length_control: boolean`\n Whether to control the length of the translated text. See the [list of languages that support length control](https://dev.writer.com/api-reference/translation-api/language-support#length-control). If the language does not support length control, this parameter is ignored.\n\n- `mask_profanity: boolean`\n Whether to mask profane words in the translated text. See the [list of languages that do not support profanity masking](https://dev.writer.com/api-reference/translation-api/language-support#profanity-masking). If the language does not support profanity masking, this parameter is ignored.\n\n- `model: 'palmyra-translate'`\n The model to use for translation.\n\n- `source_language_code: string`\n The [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) language code of the original text to translate. For example, `en` for English, `zh` for Chinese, `fr` for French, `es` for Spanish. If the language has a variant, the code appends the two-digit [ISO-3166 country code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes). For example, Mexican Spanish is `es-MX`. See the [list of supported languages and language codes](https://dev.writer.com/api-reference/translation-api/language-support).\n\n- `target_language_code: string`\n The [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) language code of the target language for the translation. For example, `en` for English, `zh` for Chinese, `fr` for French, `es` for Spanish. If the language has a variant, the code appends the two-digit [ISO-3166 country code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes). For example, Mexican Spanish is `es-MX`. See the [list of supported languages and language codes](https://dev.writer.com/api-reference/translation-api/language-support).\n\n- `text: string`\n The text to translate. Maximum of 100,000 words.\n\n### Returns\n\n- `{ data: string; }`\n\n - `data: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst translationResponse = await client.translation.translate({\n formality: true,\n length_control: true,\n mask_profanity: true,\n model: 'palmyra-translate',\n source_language_code: 'en',\n target_language_code: 'es',\n text: 'Hello, world!',\n});\n\nconsole.log(translationResponse);\n```", perLanguage: { - go: { - method: 'client.Translation.Translate', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\ttranslationResponse, err := client.Translation.Translate(context.TODO(), writersdk.TranslationTranslateParams{\n\t\tTranslationRequest: writersdk.TranslationRequestParam{\n\t\t\tFormality: writersdk.F(true),\n\t\t\tLengthControl: writersdk.F(true),\n\t\t\tMaskProfanity: writersdk.F(true),\n\t\t\tModel: writersdk.F(writersdk.TranslationRequestModelPalmyraTranslate),\n\t\t\tSourceLanguageCode: writersdk.F("en"),\n\t\t\tTargetLanguageCode: writersdk.F("es"),\n\t\t\tText: writersdk.F("Hello, world!"),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", translationResponse.Data)\n}\n', - }, - http: { + typescript: { + method: 'client.translation.translate', example: - 'curl https://api.writer.com/v1/translation \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "formality": true,\n "length_control": true,\n "mask_profanity": true,\n "model": "palmyra-translate",\n "source_language_code": "en",\n "target_language_code": "es",\n "text": "Hello, world!"\n }\'', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst translationResponse = await client.translation.translate({\n formality: true,\n length_control: true,\n mask_profanity: true,\n model: 'palmyra-translate',\n source_language_code: 'en',\n target_language_code: 'es',\n text: 'Hello, world!',\n});\n\nconsole.log(translationResponse.data);", }, python: { method: 'translation.translate', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ntranslation_response = client.translation.translate(\n formality=True,\n length_control=True,\n mask_profanity=True,\n model="palmyra-translate",\n source_language_code="en",\n target_language_code="es",\n text="Hello, world!",\n)\nprint(translation_response.data)', }, - typescript: { - method: 'client.translation.translate', + go: { + method: 'client.Translation.Translate', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst translationResponse = await client.translation.translate({\n formality: true,\n length_control: true,\n mask_profanity: true,\n model: 'palmyra-translate',\n source_language_code: 'en',\n target_language_code: 'es',\n text: 'Hello, world!',\n});\n\nconsole.log(translationResponse.data);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\ttranslationResponse, err := client.Translation.Translate(context.TODO(), writersdk.TranslationTranslateParams{\n\t\tTranslationRequest: writersdk.TranslationRequestParam{\n\t\t\tFormality: writersdk.F(true),\n\t\t\tLengthControl: writersdk.F(true),\n\t\t\tMaskProfanity: writersdk.F(true),\n\t\t\tModel: writersdk.F(writersdk.TranslationRequestModelPalmyraTranslate),\n\t\t\tSourceLanguageCode: writersdk.F("en"),\n\t\t\tTargetLanguageCode: writersdk.F("es"),\n\t\t\tText: writersdk.F("Hello, world!"),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", translationResponse.Data)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/translation \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "formality": true,\n "length_control": true,\n "mask_profanity": true,\n "model": "palmyra-translate",\n "source_language_code": "en",\n "target_language_code": "es",\n "text": "Hello, world!"\n }\'', }, }, }, @@ -1151,24 +1151,24 @@ const EMBEDDED_METHODS: MethodEntry[] = [ markdown: "## analyze\n\n`client.vision.analyze(model: 'palmyra-vision', prompt: string, variables: { file_id: string; name: string; }[]): { data: string; }`\n\n**post** `/v1/vision`\n\nSubmit images and documents with a prompt to generate an analysis. Supports JPG, PNG, PDF, and TXT files up to 7MB each.\n\n### Parameters\n\n- `model: 'palmyra-vision'`\n The model to use for image analysis.\n\n- `prompt: string`\n The prompt to use for the image analysis. The prompt must include the name of each image variable, surrounded by double curly braces (`{{}}`). For example, `Describe the difference between the image {{image_1}} and the image {{image_2}}`.\n\n- `variables: { file_id: string; name: string; }[]`\n\n### Returns\n\n- `{ data: string; }`\n\n - `data: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst visionResponse = await client.vision.analyze({\n model: 'palmyra-vision',\n prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.',\n variables: [{ file_id: 'f1234', name: 'image_1' }, { file_id: 'f9876', name: 'image_2' }],\n});\n\nconsole.log(visionResponse);\n```", perLanguage: { - go: { - method: 'client.Vision.Analyze', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tvisionResponse, err := client.Vision.Analyze(context.TODO(), writersdk.VisionAnalyzeParams{\n\t\tVisionRequest: writersdk.VisionRequestParam{\n\t\t\tModel: writersdk.F(writersdk.VisionRequestModelPalmyraVision),\n\t\t\tPrompt: writersdk.F("Describe the difference between the image {{image_1}} and the image {{image_2}}."),\n\t\t\tVariables: writersdk.F([]writersdk.VisionRequestVariableParam{{\n\t\t\t\tFileID: writersdk.F("f1234"),\n\t\t\t\tName: writersdk.F("image_1"),\n\t\t\t}, {\n\t\t\t\tFileID: writersdk.F("f9876"),\n\t\t\t\tName: writersdk.F("image_2"),\n\t\t\t}}),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", visionResponse.Data)\n}\n', - }, - http: { + typescript: { + method: 'client.vision.analyze', example: - 'curl https://api.writer.com/v1/vision \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "model": "palmyra-vision",\n "prompt": "Describe the difference between the image {{image_1}} and the image {{image_2}}.",\n "variables": [\n {\n "file_id": "f1234",\n "name": "image_1"\n },\n {\n "file_id": "f9876",\n "name": "image_2"\n }\n ]\n }\'', + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst visionResponse = await client.vision.analyze({\n model: 'palmyra-vision',\n prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.',\n variables: [\n { name: 'image_1', file_id: 'f1234' },\n { name: 'image_2', file_id: 'f9876' },\n ],\n});\n\nconsole.log(visionResponse.data);", }, python: { method: 'vision.analyze', example: 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nvision_response = client.vision.analyze(\n model="palmyra-vision",\n prompt="Describe the difference between the image {{image_1}} and the image {{image_2}}.",\n variables=[{\n "name": "image_1",\n "file_id": "f1234",\n }, {\n "name": "image_2",\n "file_id": "f9876",\n }],\n)\nprint(vision_response.data)', }, - typescript: { - method: 'client.vision.analyze', + go: { + method: 'client.Vision.Analyze', example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst visionResponse = await client.vision.analyze({\n model: 'palmyra-vision',\n prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.',\n variables: [\n { name: 'image_1', file_id: 'f1234' },\n { name: 'image_2', file_id: 'f9876' },\n ],\n});\n\nconsole.log(visionResponse.data);", + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tvisionResponse, err := client.Vision.Analyze(context.TODO(), writersdk.VisionAnalyzeParams{\n\t\tVisionRequest: writersdk.VisionRequestParam{\n\t\t\tModel: writersdk.F(writersdk.VisionRequestModelPalmyraVision),\n\t\t\tPrompt: writersdk.F("Describe the difference between the image {{image_1}} and the image {{image_2}}."),\n\t\t\tVariables: writersdk.F([]writersdk.VisionRequestVariableParam{{\n\t\t\t\tFileID: writersdk.F("f1234"),\n\t\t\t\tName: writersdk.F("image_1"),\n\t\t\t}, {\n\t\t\t\tFileID: writersdk.F("f9876"),\n\t\t\t\tName: writersdk.F("image_2"),\n\t\t\t}}),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", visionResponse.Data)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/vision \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "model": "palmyra-vision",\n "prompt": "Describe the difference between the image {{image_1}} and the image {{image_2}}.",\n "variables": [\n {\n "file_id": "f1234",\n "name": "image_1"\n },\n {\n "file_id": "f9876",\n "name": "image_2"\n }\n ]\n }\'', }, }, }, From b671b3d852b2943f44140f8ccd827100e9121149 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 15:59:00 +0000 Subject: [PATCH 05/22] chore(formatter): run prettier and eslint separately --- eslint.config.mjs | 3 - package.json | 1 - packages/mcp-server/jest.config.ts | 4 +- packages/mcp-server/src/auth.ts | 46 +- packages/mcp-server/src/code-tool-types.ts | 2 +- packages/mcp-server/src/code-tool-worker.ts | 78 +- packages/mcp-server/src/code-tool.ts | 136 +- packages/mcp-server/src/docs-search-tool.ts | 55 +- packages/mcp-server/src/http.ts | 68 +- packages/mcp-server/src/index.ts | 2 +- packages/mcp-server/src/instructions.ts | 20 +- packages/mcp-server/src/local-docs-search.ts | 1994 ++++++++--------- packages/mcp-server/src/methods.ts | 359 ++- packages/mcp-server/src/options.ts | 47 +- packages/mcp-server/src/server.ts | 104 +- packages/mcp-server/src/types.ts | 80 +- scripts/fast-format | 6 +- scripts/format | 3 +- scripts/lint | 3 + src/api-promise.ts | 2 +- src/client.ts | 494 ++-- src/core/api-promise.ts | 9 +- src/core/error.ts | 46 +- src/core/pagination.ts | 43 +- src/core/streaming.ts | 26 +- src/error.ts | 2 +- src/index.ts | 16 +- src/internal/builtin-types.ts | 23 +- src/internal/detect-platform.ts | 6 +- src/internal/errors.ts | 14 +- src/internal/headers.ts | 4 +- src/internal/parse.ts | 11 +- src/internal/request-options.ts | 7 +- src/internal/shim-types.ts | 4 +- src/internal/shims.ts | 4 +- src/internal/to-file.ts | 14 +- src/internal/types.ts | 50 +- src/internal/utils/log.ts | 37 +- src/internal/utils/uuid.ts | 8 +- src/pagination.ts | 2 +- src/resource.ts | 2 +- src/resources/applications/applications.ts | 83 +- src/resources/applications/graphs.ts | 8 +- src/resources/applications/index.ts | 26 +- src/resources/applications/jobs.ts | 23 +- src/resources/chat.ts | 24 +- src/resources/completions.ts | 29 +- src/resources/files.ts | 16 +- src/resources/graphs.ts | 77 +- src/resources/index.ts | 88 +- src/resources/models.ts | 4 +- src/resources/shared.ts | 10 +- src/resources/tools.ts | 176 +- src/resources/translation.ts | 2 +- src/resources/vision.ts | 2 +- src/streaming.ts | 2 +- src/uploads.ts | 2 +- src/version.ts | 2 +- .../applications/applications.test.ts | 35 +- .../api-resources/applications/graphs.test.ts | 13 +- tests/api-resources/applications/jobs.test.ts | 31 +- tests/api-resources/chat.test.ts | 134 +- tests/api-resources/completions.test.ts | 30 +- tests/api-resources/files.test.ts | 42 +- tests/api-resources/graphs.test.ts | 75 +- tests/api-resources/models.test.ts | 5 +- tests/api-resources/tools.test.ts | 5 +- tests/api-resources/translation.test.ts | 37 +- tests/api-resources/vision.test.ts | 27 +- tests/index.test.ts | 498 ++-- tests/streaming.test.ts | 2 +- tests/stringifyQuery.test.ts | 42 +- yarn.lock | 33 - 73 files changed, 2211 insertions(+), 3207 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 3954b642..edd23b90 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,7 +1,6 @@ // @ts-check import tseslint from 'typescript-eslint'; import unusedImports from 'eslint-plugin-unused-imports'; -import prettier from 'eslint-plugin-prettier'; export default tseslint.config( { @@ -14,11 +13,9 @@ export default tseslint.config( plugins: { '@typescript-eslint': tseslint.plugin, 'unused-imports': unusedImports, - prettier, }, rules: { 'no-unused-vars': 'off', - 'prettier/prettier': 'error', 'unused-imports/no-unused-imports': 'error', 'no-restricted-imports': [ 'error', diff --git a/package.json b/package.json index b824c951..8419e108 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "@typescript-eslint/eslint-plugin": "8.31.1", "@typescript-eslint/parser": "8.31.1", "eslint": "^9.39.1", - "eslint-plugin-prettier": "^5.4.1", "eslint-plugin-unused-imports": "^4.1.4", "fast-check": "^3.23.1", "iconv-lite": "^0.6.3", diff --git a/packages/mcp-server/jest.config.ts b/packages/mcp-server/jest.config.ts index 3080925d..359e7f4d 100644 --- a/packages/mcp-server/jest.config.ts +++ b/packages/mcp-server/jest.config.ts @@ -10,7 +10,9 @@ const config: JestConfigWithTsJest = { '^writer-sdk-mcp$': '/src/index.ts', '^writer-sdk-mcp/(.*)$': '/src/$1', }, - modulePathIgnorePatterns: ['/dist/'], + modulePathIgnorePatterns: [ + '/dist/', + ], testPathIgnorePatterns: ['scripts'], }; diff --git a/packages/mcp-server/src/auth.ts b/packages/mcp-server/src/auth.ts index 495e9823..b796c977 100644 --- a/packages/mcp-server/src/auth.ts +++ b/packages/mcp-server/src/auth.ts @@ -1,42 +1,34 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { IncomingMessage } from 'node:http'; -import { ClientOptions } from 'writer-sdk'; +import { IncomingMessage } from 'node:http' +import { ClientOptions } from 'writer-sdk' import { McpOptions } from './options'; -export const parseClientAuthHeaders = (req: IncomingMessage, required?: boolean): Partial => { - if (req.headers.authorization) { - const scheme = req.headers.authorization.split(' ')[0]!; - const value = req.headers.authorization.slice(scheme.length + 1); - switch (scheme) { - case 'Bearer': - return { apiKey: req.headers.authorization.slice('Bearer '.length) }; - default: - throw new Error( - 'Unsupported authorization scheme. Expected the "Authorization" header to be a supported scheme (Bearer).', - ); - } - } else if (required) { - throw new Error('Missing required Authorization header; see WWW-Authenticate header for details.'); +export const parseClientAuthHeaders = (req: IncomingMessage, required?: boolean): Partial => { if (req.headers.authorization) { + const scheme = req.headers.authorization.split(" ")[0]!; + const value = req.headers.authorization.slice(scheme.length + 1); + switch (scheme) { + case 'Bearer': + return { apiKey: req.headers.authorization.slice("Bearer ".length) }; + default: + throw new Error('Unsupported authorization scheme. Expected the "Authorization" header to be a supported scheme (Bearer).'); } +} else if (required) { + throw new Error('Missing required Authorization header; see WWW-Authenticate header for details.'); +} - const apiKey = - Array.isArray(req.headers['x-writer-api-key']) ? - req.headers['x-writer-api-key'][0] - : req.headers['x-writer-api-key']; - return { apiKey }; -}; +const apiKey = Array.isArray(req.headers['x-writer-api-key']) ? req.headers['x-writer-api-key'][0] : req.headers['x-writer-api-key'] +return {apiKey}; } export const getStainlessApiKey = (req: IncomingMessage, mcpOptions: McpOptions): string | undefined => { // Try to get the key from the x-stainless-api-key header - const headerKey = - Array.isArray(req.headers['x-stainless-api-key']) ? - req.headers['x-stainless-api-key'][0] - : req.headers['x-stainless-api-key']; + const headerKey = Array.isArray(req.headers['x-stainless-api-key']) ? + req.headers['x-stainless-api-key'][0] + : req.headers['x-stainless-api-key']; if (headerKey && typeof headerKey === 'string') { return headerKey; } // Fall back to value set in the mcpOptions (e.g. from environment variable), if provided return mcpOptions.stainlessApiKey; -}; +} diff --git a/packages/mcp-server/src/code-tool-types.ts b/packages/mcp-server/src/code-tool-types.ts index ace4d54e..f0b33c22 100644 --- a/packages/mcp-server/src/code-tool-types.ts +++ b/packages/mcp-server/src/code-tool-types.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { ClientOptions } from 'writer-sdk'; +import { ClientOptions } from 'writer-sdk' export type WorkerInput = { project_name: string; diff --git a/packages/mcp-server/src/code-tool-worker.ts b/packages/mcp-server/src/code-tool-worker.ts index 332af849..979445fb 100644 --- a/packages/mcp-server/src/code-tool-worker.ts +++ b/packages/mcp-server/src/code-tool-worker.ts @@ -59,8 +59,8 @@ function getTSDiagnostics(code: string): string[] { const codeWithImport = [ 'import { Writer } from "writer-sdk";', functionSource.type === 'declaration' ? - `async function run(${functionSource.client}: Writer)` - : `const run: (${functionSource.client}: Writer) => Promise =`, + `async function run(${functionSource.client}: Writer)` : + `const run: (${functionSource.client}: Writer) => Promise =`, functionSource.code, ].join('\n'); const sourcePath = path.resolve('code.ts'); @@ -108,36 +108,36 @@ function getTSDiagnostics(code: string): string[] { const fuse = new Fuse( [ - 'client.applications.generateContent', - 'client.applications.list', - 'client.applications.retrieve', - 'client.applications.jobs.create', - 'client.applications.jobs.list', - 'client.applications.jobs.retrieve', - 'client.applications.jobs.retry', - 'client.applications.graphs.list', - 'client.applications.graphs.update', - 'client.chat.chat', - 'client.completions.create', - 'client.models.list', - 'client.graphs.addFileToGraph', - 'client.graphs.create', - 'client.graphs.delete', - 'client.graphs.list', - 'client.graphs.question', - 'client.graphs.removeFileFromGraph', - 'client.graphs.retrieve', - 'client.graphs.update', - 'client.files.delete', - 'client.files.download', - 'client.files.list', - 'client.files.retrieve', - 'client.files.retry', - 'client.files.upload', - 'client.tools.parsePdf', - 'client.tools.webSearch', - 'client.translation.translate', - 'client.vision.analyze', + "client.applications.generateContent", + "client.applications.list", + "client.applications.retrieve", + "client.applications.jobs.create", + "client.applications.jobs.list", + "client.applications.jobs.retrieve", + "client.applications.jobs.retry", + "client.applications.graphs.list", + "client.applications.graphs.update", + "client.chat.chat", + "client.completions.create", + "client.models.list", + "client.graphs.addFileToGraph", + "client.graphs.create", + "client.graphs.delete", + "client.graphs.list", + "client.graphs.question", + "client.graphs.removeFileFromGraph", + "client.graphs.retrieve", + "client.graphs.update", + "client.files.delete", + "client.files.download", + "client.files.list", + "client.files.retrieve", + "client.files.retry", + "client.files.upload", + "client.tools.parsePdf", + "client.tools.webSearch", + "client.translation.translate", + "client.vision.analyze" ], { threshold: 1, shouldSort: true }, ); @@ -220,12 +220,7 @@ function parseError(code: string, error: unknown): string | undefined { // Deno uses V8; the first ":LINE:COLUMN" is the top of stack. const lineNumber = error.stack?.match(/:([0-9]+):[0-9]+/)?.[1]; // -1 for the zero-based indexing - const line = - lineNumber && - code - .split('\n') - .at(parseInt(lineNumber, 10) - 1) - ?.trim(); + const line = lineNumber && code.split('\n').at(parseInt(lineNumber, 10) - 1)?.trim(); return line ? `${message}\n at line ${lineNumber}\n ${line}` : message; } catch { return message; @@ -237,9 +232,8 @@ const fetch = async (req: Request): Promise => { const runFunctionSource = code ? getRunFunctionSource(code) : null; if (!runFunctionSource) { - const message = - code ? - 'The code is missing a top-level `run` function.' + const message = code + ? 'The code is missing a top-level `run` function.' : 'The code argument is missing. Provide one containing a top-level `run` function.'; return Response.json( { @@ -284,7 +278,7 @@ const fetch = async (req: Request): Promise => { try { let run_ = async (client: any) => {}; run_ = (await tseval(`${code}\nexport default run;`)).default; - const result = await run_(makeSdkProxy(client, { path: ['client'] })); + const result = await run_(makeSdkProxy(client, { path: ["client"] })); return Response.json({ is_error: false, result, diff --git a/packages/mcp-server/src/code-tool.ts b/packages/mcp-server/src/code-tool.ts index df578364..b1a9bd22 100644 --- a/packages/mcp-server/src/code-tool.ts +++ b/packages/mcp-server/src/code-tool.ts @@ -1,16 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { - ContentBlock, - McpRequestContext, - McpTool, - Metadata, - ToolCallResult, - asErrorResult, - asTextContentResult, -} from './types'; +import { ContentBlock, McpRequestContext, McpTool, Metadata, ToolCallResult, asErrorResult, asTextContentResult } from './types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import { readEnv, requireValue } from './util'; +import { readEnv, requireValue } from "./util"; import { WorkerInput, WorkerOutput } from './code-tool-types'; import { getLogger } from './logger'; import { SdkMethod } from './methods'; @@ -52,13 +44,10 @@ Always type dynamic key-value stores explicitly as Record * @param codeExecutionMode - Whether to execute code in a local Deno environment or in a remote * sandbox environment hosted by Stainless. */ -export function codeTool({ - blockedMethods, - codeExecutionMode, -}: { - blockedMethods: SdkMethod[] | undefined; - codeExecutionMode: McpCodeExecutionMode; -}): McpTool { +export function codeTool( + {blockedMethods, codeExecutionMode}: + {blockedMethods: SdkMethod[] | undefined, codeExecutionMode: McpCodeExecutionMode}, +): McpTool { const metadata: Metadata = { resource: 'all', operation: 'write', tags: [] }; const tool: Tool = { name: 'execute', @@ -81,13 +70,10 @@ export function codeTool({ const logger = getLogger(); - const handler = async ({ - reqContext, - args, - }: { - reqContext: McpRequestContext; - args: any; - }): Promise => { + const handler = async ( + {reqContext, args}: + {reqContext: McpRequestContext, args: any}, + ): Promise => { const code = args.code as string; // Do very basic blocking of code that includes forbidden method names. // @@ -97,11 +83,7 @@ export function codeTool({ if (blockedMethods) { const blockedMatches = blockedMethods.filter((method) => code.includes(method.fullyQualifiedName)); if (blockedMatches.length > 0) { - return asErrorResult( - `The following methods have been blocked by the MCP server and cannot be used in code execution: ${blockedMatches - .map((m) => m.fullyQualifiedName) - .join(', ')}`, - ); + return asErrorResult(`The following methods have been blocked by the MCP server and cannot be used in code execution: ${blockedMatches.map((m) => m.fullyQualifiedName).join(', ')}`); } } @@ -126,44 +108,35 @@ export function codeTool({ 'Got code tool execution result', ); return result; - }; + } return { metadata, tool, handler }; } -const remoteStainlessHandler = async ({ - reqContext, - args, -}: { - reqContext: McpRequestContext; - args: any; -}): Promise => { +const remoteStainlessHandler = async ( + {reqContext, args}: + {reqContext: McpRequestContext, args: any}, +): Promise => { const code = args.code as string; const intent = args.intent as string | undefined; const client = reqContext.client; - const codeModeEndpoint = readEnv('CODE_MODE_ENDPOINT_URL') ?? 'https://api.stainless.com/api/ai/code-tool'; + const codeModeEndpoint = readEnv("CODE_MODE_ENDPOINT_URL") ?? "https://api.stainless.com/api/ai/code-tool"; - const localClientEnvs = { - WRITER_API_KEY: requireValue( - readEnv('WRITER_API_KEY') ?? client.apiKey, - 'set WRITER_API_KEY environment variable or provide apiKey client option', - ), - WRITER_BASE_URL: readEnv('WRITER_BASE_URL') ?? client.baseURL ?? undefined, - }; + const localClientEnvs = { WRITER_API_KEY: requireValue(readEnv('WRITER_API_KEY') ?? client.apiKey, 'set WRITER_API_KEY environment variable or provide apiKey client option'), WRITER_BASE_URL: readEnv('WRITER_BASE_URL') ?? client.baseURL ?? undefined }; // Merge any upstream client envs from the request header, with upstream values taking precedence. const mergedClientEnvs = { ...localClientEnvs, ...reqContext.upstreamClientEnvs }; // Setting a Stainless API key authenticates requests to the code tool endpoint. const res = await fetch(codeModeEndpoint, { - method: 'POST', + method: "POST", headers: { - ...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey }), - 'Content-Type': 'application/json', - 'x-stainless-mcp-client-envs': JSON.stringify(mergedClientEnvs), + ...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey, }), + "Content-Type": "application/json", + "x-stainless-mcp-client-envs": JSON.stringify(mergedClientEnvs), }, body: JSON.stringify({ - project_name: 'writer', + project_name: "writer", code, intent, client_opts: {}, @@ -172,18 +145,12 @@ const remoteStainlessHandler = async ({ if (!res.ok) { if (res.status === 404 && !reqContext.stainlessApiKey) { - throw new Error( - 'Could not access code tool for this project. You may need to provide a Stainless API key via the STAINLESS_API_KEY environment variable, the --stainless-api-key flag, or the x-stainless-api-key HTTP header.', - ); + throw new Error('Could not access code tool for this project. You may need to provide a Stainless API key via the STAINLESS_API_KEY environment variable, the --stainless-api-key flag, or the x-stainless-api-key HTTP header.'); } - throw new Error( - `${res.status}: ${ - res.statusText - } error when trying to contact Code Tool server. Details: ${await res.text()}`, - ); + throw new Error(`${res.status}: ${res.statusText} error when trying to contact Code Tool server. Details: ${await res.text()}`); } - const { is_error, result, log_lines, err_lines } = (await res.json()) as WorkerOutput; + const { is_error, result, log_lines, err_lines } = await res.json() as WorkerOutput; const hasLogs = log_lines.length > 0 || err_lines.length > 0; const output = { result, @@ -191,18 +158,17 @@ const remoteStainlessHandler = async ({ ...(err_lines.length > 0 && { err_lines }), }; if (is_error) { - return asErrorResult(typeof result === 'string' && !hasLogs ? result : JSON.stringify(output, null, 2)); + return asErrorResult( + typeof result === 'string' && !hasLogs ? result : JSON.stringify(output, null, 2), + ); } return asTextContentResult(output); }; -const localDenoHandler = async ({ - reqContext, - args, -}: { - reqContext: McpRequestContext; - args: unknown; -}): Promise => { +const localDenoHandler = async ( + {reqContext, args} : + {reqContext: McpRequestContext, args: unknown}, +): Promise => { const fs = await import('node:fs'); const path = await import('node:path'); const url = await import('node:url'); @@ -227,20 +193,24 @@ const localDenoHandler = async ({ } catch { try { // Use deno binary in node_modules if it's found - const denoNodeModulesPath = path.resolve(packageNodeModulesPath, 'deno', 'bin.cjs'); + const denoNodeModulesPath = path.resolve( + packageNodeModulesPath, + 'deno', + 'bin.cjs', + ); await fs.promises.access(denoNodeModulesPath, fs.constants.X_OK); denoPath = denoNodeModulesPath; } catch { return asErrorResult( 'Deno is required for code execution but was not found. ' + - 'Install it from https://deno.land or run: npm install deno', + 'Install it from https://deno.land or run: npm install deno', ); } } const allowReadPaths = [ 'code-tool-worker.mjs', - `${workerPath.replace(/([\/\\]node_modules)[\/\\].+$/, '$1')}/`, + `${workerPath.replace(/([\/\\]node_modules)[\/\\].+$/, "$1")}/`, packageRoot, ]; @@ -274,7 +244,7 @@ const localDenoHandler = async ({ // Merge any upstream client envs into the Deno subprocess environment, // with the upstream env vars taking precedence. env: { ...process.env, ...reqContext.upstreamClientEnvs }, - }, + } }); try { @@ -286,11 +256,11 @@ const localDenoHandler = async ({ // Strip null/undefined values so that the worker SDK client can fall back to // reading from environment variables (including any upstreamClientEnvs). const opts = { - ...(client.baseURL != null ? { baseURL: client.baseURL } : undefined), - ...(client.apiKey != null ? { apiKey: client.apiKey } : undefined), - defaultHeaders: { - 'X-Stainless-MCP': 'true', - }, + ...(client.baseURL != null ? { baseURL: client.baseURL } : undefined), + ...(client.apiKey != null ? { apiKey: client.apiKey } : undefined), + defaultHeaders: { + 'X-Stainless-MCP': 'true', + }, } satisfies Partial as ClientOptions; const req = worker.request( @@ -337,12 +307,11 @@ const localDenoHandler = async ({ if (resp.status === 200) { const { result, log_lines, err_lines } = (await resp.json()) as WorkerOutput; const returnOutput: ContentBlock | null = - result == null ? null : ( - { + result == null ? null + : { type: 'text', text: typeof result === 'string' ? result : JSON.stringify(result), - } - ); + }; const logOutput: ContentBlock | null = log_lines.length === 0 ? null @@ -363,12 +332,11 @@ const localDenoHandler = async ({ } else { const { result, log_lines, err_lines } = (await resp.json()) as WorkerOutput; const messageOutput: ContentBlock | null = - result == null ? null : ( - { + result == null ? null + : { type: 'text', text: typeof result === 'string' ? result : JSON.stringify(result), - } - ); + }; const logOutput: ContentBlock | null = log_lines.length === 0 ? null diff --git a/packages/mcp-server/src/docs-search-tool.ts b/packages/mcp-server/src/docs-search-tool.ts index fb36ce2c..81f052dc 100644 --- a/packages/mcp-server/src/docs-search-tool.ts +++ b/packages/mcp-server/src/docs-search-tool.ts @@ -14,8 +14,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'search_docs', - description: - 'Search SDK documentation to find methods, parameters, and usage examples for interacting with the API. Use this before writing code when you need to discover the right approach.', + description: 'Search SDK documentation to find methods, parameters, and usage examples for interacting with the API. Use this before writing code when you need to discover the right approach.', inputSchema: { type: 'object', properties: { @@ -32,7 +31,7 @@ export const tool: Tool = { type: 'string', description: 'The amount of detail to return.', enum: ['default', 'verbose'], - }, + } }, required: ['query', 'language'], }, @@ -41,8 +40,7 @@ export const tool: Tool = { }, }; -const docsSearchURL = - process.env['DOCS_SEARCH_URL'] || 'https://api.stainless.com/api/projects/writer/docs/search'; +const docsSearchURL = process.env['DOCS_SEARCH_URL'] || 'https://api.stainless.com/api/projects/writer/docs/search' let _localSearch: LocalDocsSearch | undefined; @@ -67,27 +65,30 @@ async function searchLocal(args: Record): Promise { }).results; } -async function searchRemote(args: Record, reqContext: McpRequestContext): Promise { +async function searchRemote( + args: Record, + reqContext: McpRequestContext, +): Promise { const body = args as any; const query = new URLSearchParams(body).toString(); const startTime = Date.now(); - const result = await fetch(`${docsSearchURL}?${query}`, { - headers: { - ...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey }), - ...(reqContext.mcpSessionId && { 'x-stainless-mcp-session-id': reqContext.mcpSessionId }), - ...(reqContext.mcpClientInfo && { - 'x-stainless-mcp-client-info': JSON.stringify(reqContext.mcpClientInfo), - }), + const result = await fetch( + `${docsSearchURL}?${query}`, + { + headers: { + ...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey }), + ...(reqContext.mcpSessionId && { 'x-stainless-mcp-session-id': reqContext.mcpSessionId }), + ...(reqContext.mcpClientInfo && { 'x-stainless-mcp-client-info': JSON.stringify(reqContext.mcpClientInfo) }), + }, }, - }); + ); const logger = getLogger(); if (!result.ok) { const errorText = await result.text(); - logger.warn( - { + logger.warn({ durationMs: Date.now() - startTime, query: body.query, status: result.status, @@ -98,19 +99,14 @@ async function searchRemote(args: Record, reqContext: McpReques ); if (result.status === 404 && !reqContext.stainlessApiKey) { - throw new Error( - 'Could not find docs for this project. You may need to provide a Stainless API key via the STAINLESS_API_KEY environment variable, the --stainless-api-key flag, or the x-stainless-api-key HTTP header.', - ); + throw new Error('Could not find docs for this project. You may need to provide a Stainless API key via the STAINLESS_API_KEY environment variable, the --stainless-api-key flag, or the x-stainless-api-key HTTP header.'); } - throw new Error( - `${result.status}: ${result.statusText} when using doc search tool. Details: ${errorText}`, - ); + throw new Error(`${result.status}: ${result.statusText} when using doc search tool. Details: ${errorText}`); } const resultBody = await result.json(); - logger.info( - { + logger.info({ durationMs: Date.now() - startTime, query: body.query, }, @@ -119,13 +115,10 @@ async function searchRemote(args: Record, reqContext: McpReques return resultBody; } -export const handler = async ({ - reqContext, - args, -}: { - reqContext: McpRequestContext; - args: Record | undefined; -}) => { +export const handler = async ( + { reqContext, args }: + { reqContext: McpRequestContext; args: Record | undefined }, +) => { const body = args ?? {}; if (_localSearch) { diff --git a/packages/mcp-server/src/http.ts b/packages/mcp-server/src/http.ts index 9a5cc972..5a4155f6 100644 --- a/packages/mcp-server/src/http.ts +++ b/packages/mcp-server/src/http.ts @@ -1,7 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; -import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js' import { ClientOptions } from 'writer-sdk'; import express from 'express'; import pino from 'pino'; @@ -24,7 +24,7 @@ const newServer = async ({ }): Promise => { const stainlessApiKey = getStainlessApiKey(req, mcpOptions); const customInstructionsPath = mcpOptions.customInstructionsPath; - const server = await newMcpServer({ stainlessApiKey, customInstructionsPath }); + const server = await newMcpServer({stainlessApiKey, customInstructionsPath}); const authOptions = parseClientAuthHeaders(req, false); @@ -65,13 +65,15 @@ const newServer = async ({ ); } } catch (error) { - getLogger().warn({ error }, 'Failed to parse x-stainless-mcp-client-permissions header'); + getLogger().warn( + { error }, + 'Failed to parse x-stainless-mcp-client-permissions header', + ); } } - const mcpClientInfo = - typeof req.body?.params?.clientInfo?.name === 'string' ? - { name: req.body.params.clientInfo.name, version: String(req.body.params.clientInfo.version ?? '') } + const mcpClientInfo = typeof req.body?.params?.clientInfo?.name === 'string' + ? { name: req.body.params.clientInfo.name, version: String(req.body.params.clientInfo.version ?? '') } : undefined; await initMcpServer({ @@ -88,7 +90,10 @@ const newServer = async ({ }); if (mcpClientInfo) { - getLogger().info({ mcpSessionId: (req as any).mcpSessionId, mcpClientInfo }, 'MCP client connected'); + getLogger().info( + { mcpSessionId: (req as any).mcpSessionId, mcpClientInfo }, + 'MCP client connected', + ); } return server; @@ -128,7 +133,7 @@ const del = async (req: express.Request, res: express.Response) => { const redactHeaders = (headers: Record) => { const hiddenHeaders = /auth|cookie|key|token|x-stainless-mcp-client-envs/i; const filtered = { ...headers }; - Object.keys(filtered).forEach((key) => { + Object.keys(filtered).forEach(key => { if (hiddenHeaders.test(key)) { filtered[key] = '[REDACTED]'; } @@ -181,17 +186,17 @@ export const streamableHTTPApp = ({ req: pino.stdSerializers.wrapRequestSerializer((req) => { return { ...req, - headers: redactHeaders(req.raw.headers), + headers: redactHeaders(req.raw.headers) }; }), res: pino.stdSerializers.wrapResponseSerializer((res) => { return { ...res, - headers: redactHeaders(res.headers), + headers: redactHeaders(res.headers) }; }), - }, - }), + } + }) ); app.get('/health', async (req: express.Request, res: express.Response) => { @@ -204,24 +209,23 @@ export const streamableHTTPApp = ({ return app; }; -export const launchStreamableHTTPServer = async ({ - mcpOptions, - port, -}: { - mcpOptions: McpOptions; - port: number | string | undefined; -}) => { - const app = streamableHTTPApp({ mcpOptions }); - const server = app.listen(port); - const address = server.address(); - - const logger = getLogger(); - - if (typeof address === 'string') { - logger.info(`MCP Server running on streamable HTTP at ${address}`); - } else if (address !== null) { - logger.info(`MCP Server running on streamable HTTP on port ${address.port}`); - } else { - logger.info(`MCP Server running on streamable HTTP on port ${port}`); +export const launchStreamableHTTPServer = async( + {mcpOptions, port}: { + mcpOptions: McpOptions, + port: number | string | undefined, + } +) => { + const app = streamableHTTPApp({ mcpOptions }); + const server = app.listen(port); + const address = server.address(); + + const logger = getLogger(); + + if (typeof address === 'string') { + logger.info(`MCP Server running on streamable HTTP at ${address}`); + } else if (address !== null) { + logger.info(`MCP Server running on streamable HTTP on port ${address.port}`); + } else { + logger.info(`MCP Server running on streamable HTTP on port ${port}`); + } } -}; diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index 5bca4a60..6306dc26 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -17,7 +17,7 @@ async function main() { const selectedTools = await selectToolsOrError(options); getLogger().info( - { tools: selectedTools.map((e) => e.tool.name) }, + {tools: selectedTools.map((e) => e.tool.name)}, `MCP Server starting with ${selectedTools.length} tools`, ); diff --git a/packages/mcp-server/src/instructions.ts b/packages/mcp-server/src/instructions.ts index 8c70804c..10714a28 100644 --- a/packages/mcp-server/src/instructions.ts +++ b/packages/mcp-server/src/instructions.ts @@ -60,24 +60,24 @@ async function fetchLatestInstructionsFromApi(stainlessApiKey: string | undefine // Setting the stainless API key is optional, but may be required // to authenticate requests to the Stainless API. const response = await fetch( - readEnv('CODE_MODE_INSTRUCTIONS_URL') ?? 'https://api.stainless.com/api/ai/instructions/writer', + readEnv("CODE_MODE_INSTRUCTIONS_URL") ?? + 'https://api.stainless.com/api/ai/instructions/writer', { - method: 'GET', - headers: { ...(stainlessApiKey && { Authorization: stainlessApiKey }) }, - }, - ); + method: "GET", + headers: { ...( stainlessApiKey && { Authorization: stainlessApiKey } ) } + } + ) let instructions: string | undefined; if (!response.ok) { getLogger().warn( - 'Warning: failed to retrieve MCP server instructions. Proceeding with default instructions...', - ); + "Warning: failed to retrieve MCP server instructions. Proceeding with default instructions..." + ) - instructions = - '\n This is the writer MCP server.\n\n Available tools:\n - search_docs: Search SDK documentation to find the right methods and parameters.\n - execute: Run TypeScript code against a pre-authenticated SDK client. Define an async run(client) function.\n\n Workflow:\n - If unsure about the API, call search_docs first.\n - Write complete solutions in a single execute call when possible. For large datasets, use API filters to narrow results or paginate within a single execute block.\n - If execute returns an error, read the error and fix your code rather than retrying the same approach.\n - Variables do not persist between execute calls. Return or log all data you need.\n - Individual HTTP requests to the API have a 30-second timeout. If a request times out, try a smaller query or add filters.\n - Code execution has a total timeout of approximately 5 minutes. If your code times out, simplify it or break it into smaller steps.\n '; + instructions = "\n This is the writer MCP server.\n\n Available tools:\n - search_docs: Search SDK documentation to find the right methods and parameters.\n - execute: Run TypeScript code against a pre-authenticated SDK client. Define an async run(client) function.\n\n Workflow:\n - If unsure about the API, call search_docs first.\n - Write complete solutions in a single execute call when possible. For large datasets, use API filters to narrow results or paginate within a single execute block.\n - If execute returns an error, read the error and fix your code rather than retrying the same approach.\n - Variables do not persist between execute calls. Return or log all data you need.\n - Individual HTTP requests to the API have a 30-second timeout. If a request times out, try a smaller query or add filters.\n - Code execution has a total timeout of approximately 5 minutes. If your code times out, simplify it or break it into smaller steps.\n "; } - instructions ??= ((await response.json()) as { instructions: string }).instructions; + instructions ??= (await response.json() as { instructions: string }).instructions; return instructions; } diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index f90a9750..db78996e 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -51,1145 +51,1020 @@ type SearchResult = { const EMBEDDED_METHODS: MethodEntry[] = [ { - name: 'generate_content', - endpoint: '/v1/applications/{application_id}', - httpMethod: 'post', - summary: 'Generate from application', - description: - 'Generate content from an existing no-code agent (formerly called no-code applications) with inputs.', - stainlessPath: '(resource) applications > (method) generate_content', - qualified: 'client.applications.generateContent', - params: ['application_id: string;', 'inputs: { id: string; value: string[]; }[];', 'stream?: boolean;'], - response: '{ suggestion: string; title?: string; }', - markdown: - "## generate_content\n\n`client.applications.generateContent(application_id: string, inputs: { id: string; value: string[]; }[], stream?: boolean): { suggestion: string; title?: string; }`\n\n**post** `/v1/applications/{application_id}`\n\nGenerate content from an existing no-code agent (formerly called no-code applications) with inputs.\n\n### Parameters\n\n- `application_id: string`\n\n- `inputs: { id: string; value: string[]; }[]`\n\n- `stream?: boolean`\n Indicates whether the response should be streamed. Currently only supported for research assistant applications.\n\n### Returns\n\n- `{ suggestion: string; title?: string; }`\n\n - `suggestion: string`\n - `title?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.applications.generateContent('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { inputs: [{ id: 'id', value: ['string'] }] });\nfor await (const applicationGenerateContentChunk of stream) {\n console.log(applicationGenerateContentChunk);\n}\n```", - perLanguage: { - typescript: { - method: 'client.applications.generateContent', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGenerateContentResponse = await client.applications.generateContent(\n '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n { inputs: [{ id: 'id', value: ['string'] }] },\n);\n\nconsole.log(applicationGenerateContentResponse.suggestion);", - }, - python: { - method: 'applications.generate_content', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfor application in client.applications.generate_content(\n application_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n inputs=[{\n "id": "id",\n "value": ["string"],\n }],\n):\n print(application)', - }, - go: { - method: 'client.Applications.GenerateContent', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGenerateContentResponse, err := client.Applications.GenerateContent(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\twritersdk.ApplicationGenerateContentParams{\n\t\t\tInputs: writersdk.F([]writersdk.ApplicationGenerateContentParamsInput{{\n\t\t\t\tID: writersdk.F("id"),\n\t\t\t\tValue: writersdk.F([]string{"string"}),\n\t\t\t}}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGenerateContentResponse.Suggestion)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/applications/$APPLICATION_ID \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "inputs": [\n {\n "id": "id",\n "value": [\n "string"\n ]\n }\n ]\n }\'', - }, - }, + "name": "generate_content", + "endpoint": "/v1/applications/{application_id}", + "httpMethod": "post", + "summary": "Generate from application", + "description": "Generate content from an existing no-code agent (formerly called no-code applications) with inputs.", + "stainlessPath": "(resource) applications > (method) generate_content", + "qualified": "client.applications.generateContent", + "params": [ + "application_id: string;", + "inputs: { id: string; value: string[]; }[];", + "stream?: boolean;" + ], + "response": "{ suggestion: string; title?: string; }", + "markdown": "## generate_content\n\n`client.applications.generateContent(application_id: string, inputs: { id: string; value: string[]; }[], stream?: boolean): { suggestion: string; title?: string; }`\n\n**post** `/v1/applications/{application_id}`\n\nGenerate content from an existing no-code agent (formerly called no-code applications) with inputs.\n\n### Parameters\n\n- `application_id: string`\n\n- `inputs: { id: string; value: string[]; }[]`\n\n- `stream?: boolean`\n Indicates whether the response should be streamed. Currently only supported for research assistant applications.\n\n### Returns\n\n- `{ suggestion: string; title?: string; }`\n\n - `suggestion: string`\n - `title?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.applications.generateContent('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { inputs: [{ id: 'id', value: ['string'] }] });\nfor await (const applicationGenerateContentChunk of stream) {\n console.log(applicationGenerateContentChunk);\n}\n```", + "perLanguage": { + "typescript": { + "method": "client.applications.generateContent", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGenerateContentResponse = await client.applications.generateContent(\n '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n { inputs: [{ id: 'id', value: ['string'] }] },\n);\n\nconsole.log(applicationGenerateContentResponse.suggestion);" + }, + "python": { + "method": "applications.generate_content", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfor application in client.applications.generate_content(\n application_id=\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n inputs=[{\n \"id\": \"id\",\n \"value\": [\"string\"],\n }],\n):\n print(application)" + }, + "go": { + "method": "client.Applications.GenerateContent", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tapplicationGenerateContentResponse, err := client.Applications.GenerateContent(\n\t\tcontext.TODO(),\n\t\t\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n\t\twritersdk.ApplicationGenerateContentParams{\n\t\t\tInputs: writersdk.F([]writersdk.ApplicationGenerateContentParamsInput{{\n\t\t\t\tID: writersdk.F(\"id\"),\n\t\t\t\tValue: writersdk.F([]string{\"string\"}),\n\t\t\t}}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", applicationGenerateContentResponse.Suggestion)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/applications/$APPLICATION_ID \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"inputs\": [\n {\n \"id\": \"id\",\n \"value\": [\n \"string\"\n ]\n }\n ]\n }'" + } + } }, { - name: 'list', - endpoint: '/v1/applications', - httpMethod: 'get', - summary: 'List applications', - description: - 'Retrieves a paginated list of no-code agents (formerly called no-code applications) with optional filtering and sorting capabilities.', - stainlessPath: '(resource) applications > (method) list', - qualified: 'client.applications.list', - params: [ - 'after?: string;', - 'before?: string;', - 'limit?: number;', + "name": "list", + "endpoint": "/v1/applications", + "httpMethod": "get", + "summary": "List applications", + "description": "Retrieves a paginated list of no-code agents (formerly called no-code applications) with optional filtering and sorting capabilities.", + "stainlessPath": "(resource) applications > (method) list", + "qualified": "client.applications.list", + "params": [ + "after?: string;", + "before?: string;", + "limit?: number;", "order?: 'asc' | 'desc';", - "type?: 'generation';", + "type?: 'generation';" ], - response: - "{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }", - markdown: - "## list\n\n`client.applications.list(after?: string, before?: string, limit?: number, order?: 'asc' | 'desc', type?: 'generation'): { id: string; created_at: string; inputs: object[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n\n**get** `/v1/applications`\n\nRetrieves a paginated list of no-code agents (formerly called no-code applications) with optional filtering and sorting capabilities.\n\n### Parameters\n\n- `after?: string`\n Return results after this application ID for pagination.\n\n- `before?: string`\n Return results before this application ID for pagination.\n\n- `limit?: number`\n Maximum number of applications to return in the response.\n\n- `order?: 'asc' | 'desc'`\n Sort order for the results based on creation time.\n\n- `type?: 'generation'`\n Filter applications by their type.\n\n### Returns\n\n- `{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n Detailed application object including its input configuration.\n\n - `id: string`\n - `created_at: string`\n - `inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]`\n - `name: string`\n - `status: 'deployed' | 'draft'`\n - `type: 'generation'`\n - `updated_at: string`\n - `last_deployed_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const applicationListResponse of client.applications.list()) {\n console.log(applicationListResponse);\n}\n```", - perLanguage: { - typescript: { - method: 'client.applications.list', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const applicationListResponse of client.applications.list()) {\n console.log(applicationListResponse.id);\n}", - }, - python: { - method: 'applications.list', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\npage = client.applications.list()\npage = page.data[0]\nprint(page.id)', - }, - go: { - method: 'client.Applications.List', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Applications.List(context.TODO(), writersdk.ApplicationListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/applications \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "response": "{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }", + "markdown": "## list\n\n`client.applications.list(after?: string, before?: string, limit?: number, order?: 'asc' | 'desc', type?: 'generation'): { id: string; created_at: string; inputs: object[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n\n**get** `/v1/applications`\n\nRetrieves a paginated list of no-code agents (formerly called no-code applications) with optional filtering and sorting capabilities.\n\n### Parameters\n\n- `after?: string`\n Return results after this application ID for pagination.\n\n- `before?: string`\n Return results before this application ID for pagination.\n\n- `limit?: number`\n Maximum number of applications to return in the response.\n\n- `order?: 'asc' | 'desc'`\n Sort order for the results based on creation time.\n\n- `type?: 'generation'`\n Filter applications by their type.\n\n### Returns\n\n- `{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n Detailed application object including its input configuration.\n\n - `id: string`\n - `created_at: string`\n - `inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]`\n - `name: string`\n - `status: 'deployed' | 'draft'`\n - `type: 'generation'`\n - `updated_at: string`\n - `last_deployed_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const applicationListResponse of client.applications.list()) {\n console.log(applicationListResponse);\n}\n```", + "perLanguage": { + "typescript": { + "method": "client.applications.list", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const applicationListResponse of client.applications.list()) {\n console.log(applicationListResponse.id);\n}" + }, + "python": { + "method": "applications.list", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\npage = client.applications.list()\npage = page.data[0]\nprint(page.id)" + }, + "go": { + "method": "client.Applications.List", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tpage, err := client.Applications.List(context.TODO(), writersdk.ApplicationListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", page)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/applications \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'retrieve', - endpoint: '/v1/applications/{application_id}', - httpMethod: 'get', - summary: 'Application details', - description: - 'Retrieves detailed information for a specific no-code agent (formerly called no-code applications), including its configuration and current status.', - stainlessPath: '(resource) applications > (method) retrieve', - qualified: 'client.applications.retrieve', - params: ['application_id: string;'], - response: - "{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }", - markdown: - "## retrieve\n\n`client.applications.retrieve(application_id: string): { id: string; created_at: string; inputs: object[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n\n**get** `/v1/applications/{application_id}`\n\nRetrieves detailed information for a specific no-code agent (formerly called no-code applications), including its configuration and current status.\n\n### Parameters\n\n- `application_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n Detailed application object including its input configuration.\n\n - `id: string`\n - `created_at: string`\n - `inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]`\n - `name: string`\n - `status: 'deployed' | 'draft'`\n - `type: 'generation'`\n - `updated_at: string`\n - `last_deployed_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst application = await client.applications.retrieve('application_id');\n\nconsole.log(application);\n```", - perLanguage: { - typescript: { - method: 'client.applications.retrieve', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst application = await client.applications.retrieve('application_id');\n\nconsole.log(application.id);", - }, - python: { - method: 'applications.retrieve', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\napplication = client.applications.retrieve(\n "application_id",\n)\nprint(application.id)', - }, - go: { - method: 'client.Applications.Get', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplication, err := client.Applications.Get(context.TODO(), "application_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", application.ID)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/applications/$APPLICATION_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "name": "retrieve", + "endpoint": "/v1/applications/{application_id}", + "httpMethod": "get", + "summary": "Application details", + "description": "Retrieves detailed information for a specific no-code agent (formerly called no-code applications), including its configuration and current status.", + "stainlessPath": "(resource) applications > (method) retrieve", + "qualified": "client.applications.retrieve", + "params": [ + "application_id: string;" + ], + "response": "{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }", + "markdown": "## retrieve\n\n`client.applications.retrieve(application_id: string): { id: string; created_at: string; inputs: object[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n\n**get** `/v1/applications/{application_id}`\n\nRetrieves detailed information for a specific no-code agent (formerly called no-code applications), including its configuration and current status.\n\n### Parameters\n\n- `application_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n Detailed application object including its input configuration.\n\n - `id: string`\n - `created_at: string`\n - `inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]`\n - `name: string`\n - `status: 'deployed' | 'draft'`\n - `type: 'generation'`\n - `updated_at: string`\n - `last_deployed_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst application = await client.applications.retrieve('application_id');\n\nconsole.log(application);\n```", + "perLanguage": { + "typescript": { + "method": "client.applications.retrieve", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst application = await client.applications.retrieve('application_id');\n\nconsole.log(application.id);" + }, + "python": { + "method": "applications.retrieve", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\napplication = client.applications.retrieve(\n \"application_id\",\n)\nprint(application.id)" + }, + "go": { + "method": "client.Applications.Get", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tapplication, err := client.Applications.Get(context.TODO(), \"application_id\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", application.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/applications/$APPLICATION_ID \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'list', - endpoint: '/v1/applications/{application_id}/jobs', - httpMethod: 'get', - summary: 'Retrieve all jobs', - description: - 'Retrieve all jobs created via the async API, linked to the provided application ID (or alias).', - stainlessPath: '(resource) applications.jobs > (method) list', - qualified: 'client.applications.jobs.list', - params: [ - 'application_id: string;', - 'limit?: number;', - 'offset?: number;', - "status?: 'in_progress' | 'failed' | 'completed';", + "name": "list", + "endpoint": "/v1/applications/{application_id}/jobs", + "httpMethod": "get", + "summary": "Retrieve all jobs", + "description": "Retrieve all jobs created via the async API, linked to the provided application ID (or alias).", + "stainlessPath": "(resource) applications.jobs > (method) list", + "qualified": "client.applications.jobs.list", + "params": [ + "application_id: string;", + "limit?: number;", + "offset?: number;", + "status?: 'in_progress' | 'failed' | 'completed';" ], - response: - "{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }", - markdown: - "## list\n\n`client.applications.jobs.list(application_id: string, limit?: number, offset?: number, status?: 'in_progress' | 'failed' | 'completed'): { id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: application_generate_content_response; error?: string; updated_at?: string; }`\n\n**get** `/v1/applications/{application_id}/jobs`\n\nRetrieve all jobs created via the async API, linked to the provided application ID (or alias).\n\n### Parameters\n\n- `application_id: string`\n\n- `limit?: number`\n The pagination limit for retrieving the jobs.\n\n- `offset?: number`\n The pagination offset for retrieving the jobs.\n\n- `status?: 'in_progress' | 'failed' | 'completed'`\n The status of the job.\n\n### Returns\n\n- `{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }`\n\n - `id: string`\n - `application_id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n - `completed_at?: string`\n - `data?: { suggestion: string; title?: string; }`\n - `error?: string`\n - `updated_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const applicationGenerateAsyncResponse of client.applications.jobs.list('application_id')) {\n console.log(applicationGenerateAsyncResponse);\n}\n```", - perLanguage: { - typescript: { - method: 'client.applications.jobs.list', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const applicationGenerateAsyncResponse of client.applications.jobs.list(\n 'application_id',\n)) {\n console.log(applicationGenerateAsyncResponse.id);\n}", - }, - python: { - method: 'applications.jobs.list', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\npage = client.applications.jobs.list(\n application_id="application_id",\n)\npage = page.result[0]\nprint(page.id)', - }, - go: { - method: 'client.Applications.Jobs.List', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Applications.Jobs.List(\n\t\tcontext.TODO(),\n\t\t"application_id",\n\t\twritersdk.ApplicationJobListParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/jobs \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "response": "{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }", + "markdown": "## list\n\n`client.applications.jobs.list(application_id: string, limit?: number, offset?: number, status?: 'in_progress' | 'failed' | 'completed'): { id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: application_generate_content_response; error?: string; updated_at?: string; }`\n\n**get** `/v1/applications/{application_id}/jobs`\n\nRetrieve all jobs created via the async API, linked to the provided application ID (or alias).\n\n### Parameters\n\n- `application_id: string`\n\n- `limit?: number`\n The pagination limit for retrieving the jobs.\n\n- `offset?: number`\n The pagination offset for retrieving the jobs.\n\n- `status?: 'in_progress' | 'failed' | 'completed'`\n The status of the job.\n\n### Returns\n\n- `{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }`\n\n - `id: string`\n - `application_id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n - `completed_at?: string`\n - `data?: { suggestion: string; title?: string; }`\n - `error?: string`\n - `updated_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const applicationGenerateAsyncResponse of client.applications.jobs.list('application_id')) {\n console.log(applicationGenerateAsyncResponse);\n}\n```", + "perLanguage": { + "typescript": { + "method": "client.applications.jobs.list", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const applicationGenerateAsyncResponse of client.applications.jobs.list(\n 'application_id',\n)) {\n console.log(applicationGenerateAsyncResponse.id);\n}" + }, + "python": { + "method": "applications.jobs.list", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\npage = client.applications.jobs.list(\n application_id=\"application_id\",\n)\npage = page.result[0]\nprint(page.id)" + }, + "go": { + "method": "client.Applications.Jobs.List", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tpage, err := client.Applications.Jobs.List(\n\t\tcontext.TODO(),\n\t\t\"application_id\",\n\t\twritersdk.ApplicationJobListParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", page)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/applications/$APPLICATION_ID/jobs \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'create', - endpoint: '/v1/applications/{application_id}/jobs', - httpMethod: 'post', - summary: 'Generate from application (async)', - description: - 'Generate content asynchronously from an existing no-code agent (formerly called no-code applications) with inputs.', - stainlessPath: '(resource) applications.jobs > (method) create', - qualified: 'client.applications.jobs.create', - params: ['application_id: string;', 'inputs: { id: string; value: string[]; }[];'], - response: "{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }", - markdown: - "## create\n\n`client.applications.jobs.create(application_id: string, inputs: { id: string; value: string[]; }[]): { id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n**post** `/v1/applications/{application_id}/jobs`\n\nGenerate content asynchronously from an existing no-code agent (formerly called no-code applications) with inputs.\n\n### Parameters\n\n- `application_id: string`\n\n- `inputs: { id: string; value: string[]; }[]`\n A list of input objects to generate content for.\n\n### Returns\n\n- `{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n - `id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst job = await client.applications.jobs.create('application_id', { inputs: [{ id: 'id', value: ['string'] }] });\n\nconsole.log(job);\n```", - perLanguage: { - typescript: { - method: 'client.applications.jobs.create', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst job = await client.applications.jobs.create('application_id', {\n inputs: [{ id: 'id', value: ['string'] }],\n});\n\nconsole.log(job.id);", - }, - python: { - method: 'applications.jobs.create', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\njob = client.applications.jobs.create(\n application_id="application_id",\n inputs=[{\n "id": "id",\n "value": ["string"],\n }],\n)\nprint(job.id)', - }, - go: { - method: 'client.Applications.Jobs.New', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tjob, err := client.Applications.Jobs.New(\n\t\tcontext.TODO(),\n\t\t"application_id",\n\t\twritersdk.ApplicationJobNewParams{\n\t\t\tInputs: writersdk.F([]writersdk.ApplicationJobNewParamsInput{{\n\t\t\t\tID: writersdk.F("id"),\n\t\t\t\tValue: writersdk.F([]string{"string"}),\n\t\t\t}}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", job.ID)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/jobs \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "inputs": [\n {\n "id": "id",\n "value": [\n "string"\n ]\n }\n ]\n }\'', - }, - }, + "name": "create", + "endpoint": "/v1/applications/{application_id}/jobs", + "httpMethod": "post", + "summary": "Generate from application (async)", + "description": "Generate content asynchronously from an existing no-code agent (formerly called no-code applications) with inputs.", + "stainlessPath": "(resource) applications.jobs > (method) create", + "qualified": "client.applications.jobs.create", + "params": [ + "application_id: string;", + "inputs: { id: string; value: string[]; }[];" + ], + "response": "{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }", + "markdown": "## create\n\n`client.applications.jobs.create(application_id: string, inputs: { id: string; value: string[]; }[]): { id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n**post** `/v1/applications/{application_id}/jobs`\n\nGenerate content asynchronously from an existing no-code agent (formerly called no-code applications) with inputs.\n\n### Parameters\n\n- `application_id: string`\n\n- `inputs: { id: string; value: string[]; }[]`\n A list of input objects to generate content for.\n\n### Returns\n\n- `{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n - `id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst job = await client.applications.jobs.create('application_id', { inputs: [{ id: 'id', value: ['string'] }] });\n\nconsole.log(job);\n```", + "perLanguage": { + "typescript": { + "method": "client.applications.jobs.create", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst job = await client.applications.jobs.create('application_id', {\n inputs: [{ id: 'id', value: ['string'] }],\n});\n\nconsole.log(job.id);" + }, + "python": { + "method": "applications.jobs.create", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\njob = client.applications.jobs.create(\n application_id=\"application_id\",\n inputs=[{\n \"id\": \"id\",\n \"value\": [\"string\"],\n }],\n)\nprint(job.id)" + }, + "go": { + "method": "client.Applications.Jobs.New", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tjob, err := client.Applications.Jobs.New(\n\t\tcontext.TODO(),\n\t\t\"application_id\",\n\t\twritersdk.ApplicationJobNewParams{\n\t\t\tInputs: writersdk.F([]writersdk.ApplicationJobNewParamsInput{{\n\t\t\t\tID: writersdk.F(\"id\"),\n\t\t\t\tValue: writersdk.F([]string{\"string\"}),\n\t\t\t}}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", job.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/applications/$APPLICATION_ID/jobs \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"inputs\": [\n {\n \"id\": \"id\",\n \"value\": [\n \"string\"\n ]\n }\n ]\n }'" + } + } }, { - name: 'retry', - endpoint: '/v1/applications/jobs/{job_id}/retry', - httpMethod: 'post', - summary: 'Retry job execution', - description: - 'Re-triggers the async execution of a single job previously created via the Async api and terminated in error.', - stainlessPath: '(resource) applications.jobs > (method) retry', - qualified: 'client.applications.jobs.retry', - params: ['job_id: string;'], - response: "{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }", - markdown: - "## retry\n\n`client.applications.jobs.retry(job_id: string): { id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n**post** `/v1/applications/jobs/{job_id}/retry`\n\nRe-triggers the async execution of a single job previously created via the Async api and terminated in error.\n\n### Parameters\n\n- `job_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n - `id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.applications.jobs.retry('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(response);\n```", - perLanguage: { - typescript: { - method: 'client.applications.jobs.retry', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.applications.jobs.retry('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(response.id);", - }, - python: { - method: 'applications.jobs.retry', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.applications.jobs.retry(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(response.id)', - }, - go: { - method: 'client.Applications.Jobs.Retry', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Applications.Jobs.Retry(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.ID)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/applications/jobs/$JOB_ID/retry \\\n -X POST \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "name": "retry", + "endpoint": "/v1/applications/jobs/{job_id}/retry", + "httpMethod": "post", + "summary": "Retry job execution", + "description": "Re-triggers the async execution of a single job previously created via the Async api and terminated in error.", + "stainlessPath": "(resource) applications.jobs > (method) retry", + "qualified": "client.applications.jobs.retry", + "params": [ + "job_id: string;" + ], + "response": "{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }", + "markdown": "## retry\n\n`client.applications.jobs.retry(job_id: string): { id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n**post** `/v1/applications/jobs/{job_id}/retry`\n\nRe-triggers the async execution of a single job previously created via the Async api and terminated in error.\n\n### Parameters\n\n- `job_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n - `id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.applications.jobs.retry('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(response);\n```", + "perLanguage": { + "typescript": { + "method": "client.applications.jobs.retry", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.applications.jobs.retry('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(response.id);" + }, + "python": { + "method": "applications.jobs.retry", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nresponse = client.applications.jobs.retry(\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n)\nprint(response.id)" + }, + "go": { + "method": "client.Applications.Jobs.Retry", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tresponse, err := client.Applications.Jobs.Retry(context.TODO(), \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", response.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/applications/jobs/$JOB_ID/retry \\\n -X POST \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'retrieve', - endpoint: '/v1/applications/jobs/{job_id}', - httpMethod: 'get', - summary: 'Retrieve a single job', - description: 'Retrieves a single job created via the Async API.', - stainlessPath: '(resource) applications.jobs > (method) retrieve', - qualified: 'client.applications.jobs.retrieve', - params: ['job_id: string;'], - response: - "{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }", - markdown: - "## retrieve\n\n`client.applications.jobs.retrieve(job_id: string): { id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: application_generate_content_response; error?: string; updated_at?: string; }`\n\n**get** `/v1/applications/jobs/{job_id}`\n\nRetrieves a single job created via the Async API.\n\n### Parameters\n\n- `job_id: string`\n\n### Returns\n\n- `{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }`\n\n - `id: string`\n - `application_id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n - `completed_at?: string`\n - `data?: { suggestion: string; title?: string; }`\n - `error?: string`\n - `updated_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGenerateAsyncResponse = await client.applications.jobs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(applicationGenerateAsyncResponse);\n```", - perLanguage: { - typescript: { - method: 'client.applications.jobs.retrieve', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGenerateAsyncResponse = await client.applications.jobs.retrieve(\n '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n);\n\nconsole.log(applicationGenerateAsyncResponse.id);", - }, - python: { - method: 'applications.jobs.retrieve', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\napplication_generate_async_response = client.applications.jobs.retrieve(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(application_generate_async_response.id)', - }, - go: { - method: 'client.Applications.Jobs.Get', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGenerateAsyncResponse, err := client.Applications.Jobs.Get(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGenerateAsyncResponse.ID)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/applications/jobs/$JOB_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "name": "retrieve", + "endpoint": "/v1/applications/jobs/{job_id}", + "httpMethod": "get", + "summary": "Retrieve a single job", + "description": "Retrieves a single job created via the Async API.", + "stainlessPath": "(resource) applications.jobs > (method) retrieve", + "qualified": "client.applications.jobs.retrieve", + "params": [ + "job_id: string;" + ], + "response": "{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }", + "markdown": "## retrieve\n\n`client.applications.jobs.retrieve(job_id: string): { id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: application_generate_content_response; error?: string; updated_at?: string; }`\n\n**get** `/v1/applications/jobs/{job_id}`\n\nRetrieves a single job created via the Async API.\n\n### Parameters\n\n- `job_id: string`\n\n### Returns\n\n- `{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }`\n\n - `id: string`\n - `application_id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n - `completed_at?: string`\n - `data?: { suggestion: string; title?: string; }`\n - `error?: string`\n - `updated_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGenerateAsyncResponse = await client.applications.jobs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(applicationGenerateAsyncResponse);\n```", + "perLanguage": { + "typescript": { + "method": "client.applications.jobs.retrieve", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGenerateAsyncResponse = await client.applications.jobs.retrieve(\n '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n);\n\nconsole.log(applicationGenerateAsyncResponse.id);" + }, + "python": { + "method": "applications.jobs.retrieve", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\napplication_generate_async_response = client.applications.jobs.retrieve(\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n)\nprint(application_generate_async_response.id)" + }, + "go": { + "method": "client.Applications.Jobs.Get", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tapplicationGenerateAsyncResponse, err := client.Applications.Jobs.Get(context.TODO(), \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", applicationGenerateAsyncResponse.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/applications/jobs/$JOB_ID \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'list', - endpoint: '/v1/applications/{application_id}/graphs', - httpMethod: 'get', - summary: 'Retrieve graphs', - description: 'Retrieve Knowledge Graphs associated with a no-code agent that has chat capabilities.', - stainlessPath: '(resource) applications.graphs > (method) list', - qualified: 'client.applications.graphs.list', - params: ['application_id: string;'], - response: '{ graph_ids: string[]; }', - markdown: - "## list\n\n`client.applications.graphs.list(application_id: string): { graph_ids: string[]; }`\n\n**get** `/v1/applications/{application_id}/graphs`\n\nRetrieve Knowledge Graphs associated with a no-code agent that has chat capabilities.\n\n### Parameters\n\n- `application_id: string`\n\n### Returns\n\n- `{ graph_ids: string[]; }`\n\n - `graph_ids: string[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGraphsResponse = await client.applications.graphs.list('application_id');\n\nconsole.log(applicationGraphsResponse);\n```", - perLanguage: { - typescript: { - method: 'client.applications.graphs.list', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGraphsResponse = await client.applications.graphs.list('application_id');\n\nconsole.log(applicationGraphsResponse.graph_ids);", - }, - python: { - method: 'applications.graphs.list', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\napplication_graphs_response = client.applications.graphs.list(\n "application_id",\n)\nprint(application_graphs_response.graph_ids)', - }, - go: { - method: 'client.Applications.Graphs.List', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGraphsResponse, err := client.Applications.Graphs.List(context.TODO(), "application_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGraphsResponse.GraphIDs)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/graphs \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "name": "list", + "endpoint": "/v1/applications/{application_id}/graphs", + "httpMethod": "get", + "summary": "Retrieve graphs", + "description": "Retrieve Knowledge Graphs associated with a no-code agent that has chat capabilities.", + "stainlessPath": "(resource) applications.graphs > (method) list", + "qualified": "client.applications.graphs.list", + "params": [ + "application_id: string;" + ], + "response": "{ graph_ids: string[]; }", + "markdown": "## list\n\n`client.applications.graphs.list(application_id: string): { graph_ids: string[]; }`\n\n**get** `/v1/applications/{application_id}/graphs`\n\nRetrieve Knowledge Graphs associated with a no-code agent that has chat capabilities.\n\n### Parameters\n\n- `application_id: string`\n\n### Returns\n\n- `{ graph_ids: string[]; }`\n\n - `graph_ids: string[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGraphsResponse = await client.applications.graphs.list('application_id');\n\nconsole.log(applicationGraphsResponse);\n```", + "perLanguage": { + "typescript": { + "method": "client.applications.graphs.list", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGraphsResponse = await client.applications.graphs.list('application_id');\n\nconsole.log(applicationGraphsResponse.graph_ids);" + }, + "python": { + "method": "applications.graphs.list", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\napplication_graphs_response = client.applications.graphs.list(\n \"application_id\",\n)\nprint(application_graphs_response.graph_ids)" + }, + "go": { + "method": "client.Applications.Graphs.List", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tapplicationGraphsResponse, err := client.Applications.Graphs.List(context.TODO(), \"application_id\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", applicationGraphsResponse.GraphIDs)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/applications/$APPLICATION_ID/graphs \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'update', - endpoint: '/v1/applications/{application_id}/graphs', - httpMethod: 'put', - summary: 'Associate graphs', - description: 'Updates the list of Knowledge Graphs associated with a no-code chat agent.', - stainlessPath: '(resource) applications.graphs > (method) update', - qualified: 'client.applications.graphs.update', - params: ['application_id: string;', 'graph_ids: string[];'], - response: '{ graph_ids: string[]; }', - markdown: - "## update\n\n`client.applications.graphs.update(application_id: string, graph_ids: string[]): { graph_ids: string[]; }`\n\n**put** `/v1/applications/{application_id}/graphs`\n\nUpdates the list of Knowledge Graphs associated with a no-code chat agent.\n\n### Parameters\n\n- `application_id: string`\n\n- `graph_ids: string[]`\n A list of Knowledge Graph IDs to associate with the application. Note that this will replace the existing list of Knowledge Graphs associated with the application, not add to it.\n\n### Returns\n\n- `{ graph_ids: string[]; }`\n\n - `graph_ids: string[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGraphsResponse = await client.applications.graphs.update('application_id', { graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(applicationGraphsResponse);\n```", - perLanguage: { - typescript: { - method: 'client.applications.graphs.update', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGraphsResponse = await client.applications.graphs.update('application_id', {\n graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'],\n});\n\nconsole.log(applicationGraphsResponse.graph_ids);", - }, - python: { - method: 'applications.graphs.update', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\napplication_graphs_response = client.applications.graphs.update(\n application_id="application_id",\n graph_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],\n)\nprint(application_graphs_response.graph_ids)', - }, - go: { - method: 'client.Applications.Graphs.Update', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGraphsResponse, err := client.Applications.Graphs.Update(\n\t\tcontext.TODO(),\n\t\t"application_id",\n\t\twritersdk.ApplicationGraphUpdateParams{\n\t\t\tGraphIDs: writersdk.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGraphsResponse.GraphIDs)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/graphs \\\n -X PUT \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "graph_ids": [\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"\n ]\n }\'', - }, - }, + "name": "update", + "endpoint": "/v1/applications/{application_id}/graphs", + "httpMethod": "put", + "summary": "Associate graphs", + "description": "Updates the list of Knowledge Graphs associated with a no-code chat agent.", + "stainlessPath": "(resource) applications.graphs > (method) update", + "qualified": "client.applications.graphs.update", + "params": [ + "application_id: string;", + "graph_ids: string[];" + ], + "response": "{ graph_ids: string[]; }", + "markdown": "## update\n\n`client.applications.graphs.update(application_id: string, graph_ids: string[]): { graph_ids: string[]; }`\n\n**put** `/v1/applications/{application_id}/graphs`\n\nUpdates the list of Knowledge Graphs associated with a no-code chat agent.\n\n### Parameters\n\n- `application_id: string`\n\n- `graph_ids: string[]`\n A list of Knowledge Graph IDs to associate with the application. Note that this will replace the existing list of Knowledge Graphs associated with the application, not add to it.\n\n### Returns\n\n- `{ graph_ids: string[]; }`\n\n - `graph_ids: string[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGraphsResponse = await client.applications.graphs.update('application_id', { graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(applicationGraphsResponse);\n```", + "perLanguage": { + "typescript": { + "method": "client.applications.graphs.update", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGraphsResponse = await client.applications.graphs.update('application_id', {\n graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'],\n});\n\nconsole.log(applicationGraphsResponse.graph_ids);" + }, + "python": { + "method": "applications.graphs.update", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\napplication_graphs_response = client.applications.graphs.update(\n application_id=\"application_id\",\n graph_ids=[\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"],\n)\nprint(application_graphs_response.graph_ids)" + }, + "go": { + "method": "client.Applications.Graphs.Update", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tapplicationGraphsResponse, err := client.Applications.Graphs.Update(\n\t\tcontext.TODO(),\n\t\t\"application_id\",\n\t\twritersdk.ApplicationGraphUpdateParams{\n\t\t\tGraphIDs: writersdk.F([]string{\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", applicationGraphsResponse.GraphIDs)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/applications/$APPLICATION_ID/graphs \\\n -X PUT \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"graph_ids\": [\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"\n ]\n }'" + } + } }, { - name: 'chat', - endpoint: '/v1/chat', - httpMethod: 'post', - summary: 'Chat completion', - description: - 'Generate a chat completion based on the provided messages. The response shown below is for non-streaming. To learn about streaming responses, see the [chat completion guide](https://dev.writer.com/home/chat-completion).', - stainlessPath: '(resource) chat > (method) chat', - qualified: 'client.chat.chat', - params: [ + "name": "chat", + "endpoint": "/v1/chat", + "httpMethod": "post", + "summary": "Chat completion", + "description": "Generate a chat completion based on the provided messages. The response shown below is for non-streaming. To learn about streaming responses, see the [chat completion guide](https://dev.writer.com/home/chat-completion).", + "stainlessPath": "(resource) chat > (method) chat", + "qualified": "client.chat.chat", + "params": [ "messages: { role: 'user' | 'assistant' | 'system' | 'tool'; content?: string | { text: string; type: 'text'; } | { image_url: { url: string; }; type: 'image_url'; }[]; graph_data?: { references?: { files?: object[]; web?: object[]; }; sources?: object[]; status?: 'processing' | 'finished'; subqueries?: { answer: string; query: string; sources: source[]; }[]; }; name?: string; refusal?: string; tool_call_id?: string; tool_calls?: { id: string; function: { arguments: string; name?: string; }; type: 'function'; index?: number; }[]; }[];", - 'model: string;', - 'logprobs?: boolean;', - 'max_tokens?: number;', - 'n?: number;', + "model: string;", + "logprobs?: boolean;", + "max_tokens?: number;", + "n?: number;", "response_format?: { type: 'text' | 'json_schema'; json_schema?: object; };", - 'stop?: string[] | string;', - 'stream?: boolean;', - 'stream_options?: { include_usage: boolean; };', - 'temperature?: number;', + "stop?: string[] | string;", + "stream?: boolean;", + "stream_options?: { include_usage: boolean; };", + "temperature?: number;", "tool_choice?: { value: 'none' | 'auto' | 'required'; } | { value: object; };", "tools?: { function: { name: string; description?: string; parameters?: function_params; }; type: 'function'; } | { function: { graph_ids: string[]; subqueries: boolean; description?: string; query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }; }; type: 'graph'; } | { function: { description: string; model: string; }; type: 'llm'; } | { function: { formality: boolean; length_control: boolean; mask_profanity: boolean; model: 'palmyra-translate'; source_language_code?: string; target_language_code?: string; }; type: 'translation'; } | { function: { model: 'palmyra-vision'; variables: { file_id: string; name: string; }[]; }; type: 'vision'; } | { function: { exclude_domains: string[]; include_domains: string[]; }; type: 'web_search'; }[];", - 'top_p?: number;', + "top_p?: number;" ], - response: - "{ id: string; choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: chat_completion_message; logprobs?: logprobs; }[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: object; prompt_token_details?: object; }; }", - markdown: - "## chat\n\n`client.chat.chat(messages: { role: 'user' | 'assistant' | 'system' | 'tool'; content?: string | { text: string; type: 'text'; } | { image_url: object; type: 'image_url'; }[]; graph_data?: object; name?: string; refusal?: string; tool_call_id?: string; tool_calls?: object[]; }[], model: string, logprobs?: boolean, max_tokens?: number, n?: number, response_format?: { type: 'text' | 'json_schema'; json_schema?: object; }, stop?: string[] | string, stream?: boolean, stream_options?: { include_usage: boolean; }, temperature?: number, tool_choice?: { value: 'none' | 'auto' | 'required'; } | { value: object; }, tools?: { function: function_definition; type: 'function'; } | { function: object; type: 'graph'; } | { function: object; type: 'llm'; } | { function: object; type: 'translation'; } | { function: object; type: 'vision'; } | { function: object; type: 'web_search'; }[], top_p?: number): { id: string; choices: chat_completion_choice[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: chat_completion_usage; }`\n\n**post** `/v1/chat`\n\nGenerate a chat completion based on the provided messages. The response shown below is for non-streaming. To learn about streaming responses, see the [chat completion guide](https://dev.writer.com/home/chat-completion).\n\n### Parameters\n\n- `messages: { role: 'user' | 'assistant' | 'system' | 'tool'; content?: string | { text: string; type: 'text'; } | { image_url: { url: string; }; type: 'image_url'; }[]; graph_data?: { references?: { files?: object[]; web?: object[]; }; sources?: object[]; status?: 'processing' | 'finished'; subqueries?: { answer: string; query: string; sources: source[]; }[]; }; name?: string; refusal?: string; tool_call_id?: string; tool_calls?: { id: string; function: { arguments: string; name?: string; }; type: 'function'; index?: number; }[]; }[]`\n An array of message objects that form the conversation history or context for the model to respond to. The array must contain at least one message.\n\n- `model: string`\n The [ID of the model](https://dev.writer.com/home/models) to use for creating the chat completion. Supports `palmyra-x5`, `palmyra-x4`, `palmyra-fin`, `palmyra-med`, `palmyra-creative`, and `palmyra-x-003-instruct`.\n\n- `logprobs?: boolean`\n Specifies whether to return log probabilities of the output tokens.\n\n- `max_tokens?: number`\n Defines the maximum number of tokens (words and characters) that the model can generate in the response. This can be adjusted to allow for longer or shorter responses as needed. The maximum value varies by model. See the [models overview](/home/models) for more information about the maximum number of tokens for each model.\n\n- `n?: number`\n Specifies the number of completions (responses) to generate from the model in a single request. This parameter allows for generating multiple responses, offering a variety of potential replies from which to choose.\n\n- `response_format?: { type: 'text' | 'json_schema'; json_schema?: object; }`\n The response format to use for the chat completion, available with `palmyra-x4` and `palmyra-x5`.\n\n`text` is the default response format. [JSON Schema](https://json-schema.org/) is supported for structured responses. If you specify `json_schema`, you must also provide a `json_schema` object.\n - `type: 'text' | 'json_schema'`\n The type of response format to use.\n - `json_schema?: object`\n The JSON schema to use for the response format.\n\n- `stop?: string[] | string`\n A token or sequence of tokens that, when generated, will cause the model to stop producing further content. This can be a single token or an array of tokens, acting as a signal to end the output.\n\n- `stream?: boolean`\n Indicates whether the response should be streamed incrementally as it is generated or only returned once fully complete. Streaming can be useful for providing real-time feedback in interactive applications.\n\n- `stream_options?: { include_usage: boolean; }`\n Additional options for streaming.\n - `include_usage: boolean`\n Indicate whether to include usage information.\n\n- `temperature?: number`\n Controls the randomness or creativity of the model's responses. A higher temperature results in more varied and less predictable text, while a lower temperature produces more deterministic and conservative outputs.\n\n- `tool_choice?: { value: 'none' | 'auto' | 'required'; } | { value: object; }`\n Configure how the model will call functions:\n- `auto`: allows the model to automatically choose the tool to use, or not call a tool\n- `none`: disables tool calling; the model will instead generate a message\n- `required`: requires the model to call one or more tools\n\nYou can also use a JSON object to force the model to call a specific tool. For example, `{\"type\": \"function\", \"function\": {\"name\": \"get_current_weather\"}}` requires the model to call the `get_current_weather` function, regardless of the prompt.\n\n- `tools?: { function: { name: string; description?: string; parameters?: function_params; }; type: 'function'; } | { function: { graph_ids: string[]; subqueries: boolean; description?: string; query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }; }; type: 'graph'; } | { function: { description: string; model: string; }; type: 'llm'; } | { function: { formality: boolean; length_control: boolean; mask_profanity: boolean; model: 'palmyra-translate'; source_language_code?: string; target_language_code?: string; }; type: 'translation'; } | { function: { model: 'palmyra-vision'; variables: { file_id: string; name: string; }[]; }; type: 'vision'; } | { function: { exclude_domains: string[]; include_domains: string[]; }; type: 'web_search'; }[]`\n An array containing tool definitions for tools that the model can use to generate responses. The tool definitions use JSON schema. You can define your own functions or use one of the built-in `graph`, `llm`, `translation`, or `vision` tools. Note that you can only use one built-in tool type in the array (only one of `graph`, `llm`, `translation`, or `vision`). You can pass multiple [custom tools](https://dev.writer.com/home/tool-calling) of type `function` in the same request.\n\n- `top_p?: number`\n Sets the threshold for \"nucleus sampling,\" a technique to focus the model's token generation on the most likely subset of tokens. Only tokens with cumulative probability above this threshold are considered, controlling the trade-off between creativity and coherence.\n\n### Returns\n\n- `{ id: string; choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: chat_completion_message; logprobs?: logprobs; }[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: object; prompt_token_details?: object; }; }`\n\n - `id: string`\n - `choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: { content: string; refusal: string; role: 'assistant'; graph_data?: graph_data; llm_data?: object; tool_calls?: tool_call[]; translation_data?: object; web_search_data?: object; }; logprobs?: { content: logprobs_token[]; refusal: logprobs_token[]; }; }[]`\n - `created: number`\n - `model: string`\n - `object: 'chat.completion'`\n - `service_tier?: string`\n - `system_fingerprint?: string`\n - `usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: { reasoning_tokens: number; }; prompt_token_details?: { cached_tokens: number; }; }`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.chat.chat({ messages: [{ role: 'user' }], model: 'model' });\nfor await (const chatCompletionChunk of stream) {\n console.log(chatCompletionChunk);\n}\n```", - perLanguage: { - typescript: { - method: 'client.chat.chat', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst chatCompletion = await client.chat.chat({ messages: [{ role: 'user' }], model: 'model' });\n\nconsole.log(chatCompletion.id);", - }, - python: { - method: 'chat.chat', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfor chat in client.chat.chat(\n messages=[{\n "role": "user"\n }],\n model="model",\n):\n print(chat)', - }, - go: { - method: 'client.Chat.Chat', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tchatCompletion, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("model"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chatCompletion.ID)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/chat \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "messages": [\n {\n "role": "user"\n }\n ],\n "model": "model"\n }\'', - }, - }, + "response": "{ id: string; choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: chat_completion_message; logprobs?: logprobs; }[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: object; prompt_token_details?: object; }; }", + "markdown": "## chat\n\n`client.chat.chat(messages: { role: 'user' | 'assistant' | 'system' | 'tool'; content?: string | { text: string; type: 'text'; } | { image_url: object; type: 'image_url'; }[]; graph_data?: object; name?: string; refusal?: string; tool_call_id?: string; tool_calls?: object[]; }[], model: string, logprobs?: boolean, max_tokens?: number, n?: number, response_format?: { type: 'text' | 'json_schema'; json_schema?: object; }, stop?: string[] | string, stream?: boolean, stream_options?: { include_usage: boolean; }, temperature?: number, tool_choice?: { value: 'none' | 'auto' | 'required'; } | { value: object; }, tools?: { function: function_definition; type: 'function'; } | { function: object; type: 'graph'; } | { function: object; type: 'llm'; } | { function: object; type: 'translation'; } | { function: object; type: 'vision'; } | { function: object; type: 'web_search'; }[], top_p?: number): { id: string; choices: chat_completion_choice[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: chat_completion_usage; }`\n\n**post** `/v1/chat`\n\nGenerate a chat completion based on the provided messages. The response shown below is for non-streaming. To learn about streaming responses, see the [chat completion guide](https://dev.writer.com/home/chat-completion).\n\n### Parameters\n\n- `messages: { role: 'user' | 'assistant' | 'system' | 'tool'; content?: string | { text: string; type: 'text'; } | { image_url: { url: string; }; type: 'image_url'; }[]; graph_data?: { references?: { files?: object[]; web?: object[]; }; sources?: object[]; status?: 'processing' | 'finished'; subqueries?: { answer: string; query: string; sources: source[]; }[]; }; name?: string; refusal?: string; tool_call_id?: string; tool_calls?: { id: string; function: { arguments: string; name?: string; }; type: 'function'; index?: number; }[]; }[]`\n An array of message objects that form the conversation history or context for the model to respond to. The array must contain at least one message.\n\n- `model: string`\n The [ID of the model](https://dev.writer.com/home/models) to use for creating the chat completion. Supports `palmyra-x5`, `palmyra-x4`, `palmyra-fin`, `palmyra-med`, `palmyra-creative`, and `palmyra-x-003-instruct`.\n\n- `logprobs?: boolean`\n Specifies whether to return log probabilities of the output tokens.\n\n- `max_tokens?: number`\n Defines the maximum number of tokens (words and characters) that the model can generate in the response. This can be adjusted to allow for longer or shorter responses as needed. The maximum value varies by model. See the [models overview](/home/models) for more information about the maximum number of tokens for each model.\n\n- `n?: number`\n Specifies the number of completions (responses) to generate from the model in a single request. This parameter allows for generating multiple responses, offering a variety of potential replies from which to choose.\n\n- `response_format?: { type: 'text' | 'json_schema'; json_schema?: object; }`\n The response format to use for the chat completion, available with `palmyra-x4` and `palmyra-x5`.\n\n`text` is the default response format. [JSON Schema](https://json-schema.org/) is supported for structured responses. If you specify `json_schema`, you must also provide a `json_schema` object.\n - `type: 'text' | 'json_schema'`\n The type of response format to use.\n - `json_schema?: object`\n The JSON schema to use for the response format.\n\n- `stop?: string[] | string`\n A token or sequence of tokens that, when generated, will cause the model to stop producing further content. This can be a single token or an array of tokens, acting as a signal to end the output.\n\n- `stream?: boolean`\n Indicates whether the response should be streamed incrementally as it is generated or only returned once fully complete. Streaming can be useful for providing real-time feedback in interactive applications.\n\n- `stream_options?: { include_usage: boolean; }`\n Additional options for streaming.\n - `include_usage: boolean`\n Indicate whether to include usage information.\n\n- `temperature?: number`\n Controls the randomness or creativity of the model's responses. A higher temperature results in more varied and less predictable text, while a lower temperature produces more deterministic and conservative outputs.\n\n- `tool_choice?: { value: 'none' | 'auto' | 'required'; } | { value: object; }`\n Configure how the model will call functions:\n- `auto`: allows the model to automatically choose the tool to use, or not call a tool\n- `none`: disables tool calling; the model will instead generate a message\n- `required`: requires the model to call one or more tools\n\nYou can also use a JSON object to force the model to call a specific tool. For example, `{\"type\": \"function\", \"function\": {\"name\": \"get_current_weather\"}}` requires the model to call the `get_current_weather` function, regardless of the prompt.\n\n- `tools?: { function: { name: string; description?: string; parameters?: function_params; }; type: 'function'; } | { function: { graph_ids: string[]; subqueries: boolean; description?: string; query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }; }; type: 'graph'; } | { function: { description: string; model: string; }; type: 'llm'; } | { function: { formality: boolean; length_control: boolean; mask_profanity: boolean; model: 'palmyra-translate'; source_language_code?: string; target_language_code?: string; }; type: 'translation'; } | { function: { model: 'palmyra-vision'; variables: { file_id: string; name: string; }[]; }; type: 'vision'; } | { function: { exclude_domains: string[]; include_domains: string[]; }; type: 'web_search'; }[]`\n An array containing tool definitions for tools that the model can use to generate responses. The tool definitions use JSON schema. You can define your own functions or use one of the built-in `graph`, `llm`, `translation`, or `vision` tools. Note that you can only use one built-in tool type in the array (only one of `graph`, `llm`, `translation`, or `vision`). You can pass multiple [custom tools](https://dev.writer.com/home/tool-calling) of type `function` in the same request.\n\n- `top_p?: number`\n Sets the threshold for \"nucleus sampling,\" a technique to focus the model's token generation on the most likely subset of tokens. Only tokens with cumulative probability above this threshold are considered, controlling the trade-off between creativity and coherence.\n\n### Returns\n\n- `{ id: string; choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: chat_completion_message; logprobs?: logprobs; }[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: object; prompt_token_details?: object; }; }`\n\n - `id: string`\n - `choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: { content: string; refusal: string; role: 'assistant'; graph_data?: graph_data; llm_data?: object; tool_calls?: tool_call[]; translation_data?: object; web_search_data?: object; }; logprobs?: { content: logprobs_token[]; refusal: logprobs_token[]; }; }[]`\n - `created: number`\n - `model: string`\n - `object: 'chat.completion'`\n - `service_tier?: string`\n - `system_fingerprint?: string`\n - `usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: { reasoning_tokens: number; }; prompt_token_details?: { cached_tokens: number; }; }`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.chat.chat({ messages: [{ role: 'user' }], model: 'model' });\nfor await (const chatCompletionChunk of stream) {\n console.log(chatCompletionChunk);\n}\n```", + "perLanguage": { + "typescript": { + "method": "client.chat.chat", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst chatCompletion = await client.chat.chat({ messages: [{ role: 'user' }], model: 'model' });\n\nconsole.log(chatCompletion.id);" + }, + "python": { + "method": "chat.chat", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfor chat in client.chat.chat(\n messages=[{\n \"role\": \"user\"\n }],\n model=\"model\",\n):\n print(chat)" + }, + "go": { + "method": "client.Chat.Chat", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tchatCompletion, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F(\"model\"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", chatCompletion.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/chat \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"messages\": [\n {\n \"role\": \"user\"\n }\n ],\n \"model\": \"model\"\n }'" + } + } }, { - name: 'create', - endpoint: '/v1/completions', - httpMethod: 'post', - summary: 'Text generation', - description: - "Generate text completions using the specified model and prompt. This endpoint is useful for text generation tasks that don't require conversational context.", - stainlessPath: '(resource) completions > (method) create', - qualified: 'client.completions.create', - params: [ - 'model: string;', - 'prompt: string;', - 'best_of?: number;', - 'max_tokens?: number;', - 'random_seed?: number;', - 'stop?: string[] | string;', - 'stream?: boolean;', - 'temperature?: number;', - 'top_p?: number;', + "name": "create", + "endpoint": "/v1/completions", + "httpMethod": "post", + "summary": "Text generation", + "description": "Generate text completions using the specified model and prompt. This endpoint is useful for text generation tasks that don't require conversational context.", + "stainlessPath": "(resource) completions > (method) create", + "qualified": "client.completions.create", + "params": [ + "model: string;", + "prompt: string;", + "best_of?: number;", + "max_tokens?: number;", + "random_seed?: number;", + "stop?: string[] | string;", + "stream?: boolean;", + "temperature?: number;", + "top_p?: number;" ], - response: '{ choices: { text: string; log_probs?: object; }[]; model?: string; }', - markdown: - "## create\n\n`client.completions.create(model: string, prompt: string, best_of?: number, max_tokens?: number, random_seed?: number, stop?: string[] | string, stream?: boolean, temperature?: number, top_p?: number): { choices: object[]; model?: string; }`\n\n**post** `/v1/completions`\n\nGenerate text completions using the specified model and prompt. This endpoint is useful for text generation tasks that don't require conversational context.\n\n### Parameters\n\n- `model: string`\n The [ID of the model](https://dev.writer.com/home/models) to use for generating text. Supports `palmyra-x5`, `palmyra-x4`, `palmyra-fin`, `palmyra-med`, `palmyra-creative`, and `palmyra-x-003-instruct`.\n\n- `prompt: string`\n The input text that the model will process to generate a response.\n\n- `best_of?: number`\n Specifies the number of completions to generate and return the best one. Useful for generating multiple outputs and choosing the best based on some criteria.\n\n- `max_tokens?: number`\n The maximum number of tokens that the model can generate in the response.\n\n- `random_seed?: number`\n A seed used to initialize the random number generator for the model, ensuring reproducibility of the output when the same inputs are provided.\n\n- `stop?: string[] | string`\n Specifies stopping conditions for the model's output generation. This can be an array of strings or a single string that the model will look for as a signal to stop generating further tokens.\n\n- `stream?: boolean`\n Determines whether the model's output should be streamed. If true, the output is generated and sent incrementally, which can be useful for real-time applications.\n\n- `temperature?: number`\n Controls the randomness of the model's outputs. Higher values lead to more random outputs, while lower values make the model more deterministic.\n\n- `top_p?: number`\n Used to control the nucleus sampling, where only the most probable tokens with a cumulative probability of top_p are considered for sampling, providing a way to fine-tune the randomness of predictions.\n\n### Returns\n\n- `{ choices: { text: string; log_probs?: object; }[]; model?: string; }`\n\n - `choices: { text: string; log_probs?: { content: object[]; refusal: object[]; }; }[]`\n - `model?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.completions.create({ model: 'palmyra-x-003-instruct', prompt: 'Write me an SEO article about...' });\nfor await (const completionChunk of stream) {\n console.log(completionChunk);\n}\n```", - perLanguage: { - typescript: { - method: 'client.completions.create', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst completion = await client.completions.create({\n model: 'palmyra-x-003-instruct',\n prompt: 'Write me an SEO article about...',\n});\n\nconsole.log(completion.choices);", - }, - python: { - method: 'completions.create', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfor completion in client.completions.create(\n model="palmyra-x-003-instruct",\n prompt="Write me an SEO article about...",\n):\n print(completion)', - }, - go: { - method: 'client.Completions.New', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tcompletion, err := client.Completions.New(context.TODO(), writersdk.CompletionNewParams{\n\t\tModel: writersdk.F("palmyra-x-003-instruct"),\n\t\tPrompt: writersdk.F("Write me an SEO article about..."),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", completion.Choices)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/completions \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "model": "palmyra-x-003-instruct",\n "prompt": "Write me an SEO article about..."\n }\'', - }, - }, + "response": "{ choices: { text: string; log_probs?: object; }[]; model?: string; }", + "markdown": "## create\n\n`client.completions.create(model: string, prompt: string, best_of?: number, max_tokens?: number, random_seed?: number, stop?: string[] | string, stream?: boolean, temperature?: number, top_p?: number): { choices: object[]; model?: string; }`\n\n**post** `/v1/completions`\n\nGenerate text completions using the specified model and prompt. This endpoint is useful for text generation tasks that don't require conversational context.\n\n### Parameters\n\n- `model: string`\n The [ID of the model](https://dev.writer.com/home/models) to use for generating text. Supports `palmyra-x5`, `palmyra-x4`, `palmyra-fin`, `palmyra-med`, `palmyra-creative`, and `palmyra-x-003-instruct`.\n\n- `prompt: string`\n The input text that the model will process to generate a response.\n\n- `best_of?: number`\n Specifies the number of completions to generate and return the best one. Useful for generating multiple outputs and choosing the best based on some criteria.\n\n- `max_tokens?: number`\n The maximum number of tokens that the model can generate in the response.\n\n- `random_seed?: number`\n A seed used to initialize the random number generator for the model, ensuring reproducibility of the output when the same inputs are provided.\n\n- `stop?: string[] | string`\n Specifies stopping conditions for the model's output generation. This can be an array of strings or a single string that the model will look for as a signal to stop generating further tokens.\n\n- `stream?: boolean`\n Determines whether the model's output should be streamed. If true, the output is generated and sent incrementally, which can be useful for real-time applications.\n\n- `temperature?: number`\n Controls the randomness of the model's outputs. Higher values lead to more random outputs, while lower values make the model more deterministic.\n\n- `top_p?: number`\n Used to control the nucleus sampling, where only the most probable tokens with a cumulative probability of top_p are considered for sampling, providing a way to fine-tune the randomness of predictions.\n\n### Returns\n\n- `{ choices: { text: string; log_probs?: object; }[]; model?: string; }`\n\n - `choices: { text: string; log_probs?: { content: object[]; refusal: object[]; }; }[]`\n - `model?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.completions.create({ model: 'palmyra-x-003-instruct', prompt: 'Write me an SEO article about...' });\nfor await (const completionChunk of stream) {\n console.log(completionChunk);\n}\n```", + "perLanguage": { + "typescript": { + "method": "client.completions.create", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst completion = await client.completions.create({\n model: 'palmyra-x-003-instruct',\n prompt: 'Write me an SEO article about...',\n});\n\nconsole.log(completion.choices);" + }, + "python": { + "method": "completions.create", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfor completion in client.completions.create(\n model=\"palmyra-x-003-instruct\",\n prompt=\"Write me an SEO article about...\",\n):\n print(completion)" + }, + "go": { + "method": "client.Completions.New", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tcompletion, err := client.Completions.New(context.TODO(), writersdk.CompletionNewParams{\n\t\tModel: writersdk.F(\"palmyra-x-003-instruct\"),\n\t\tPrompt: writersdk.F(\"Write me an SEO article about...\"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", completion.Choices)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/completions \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"model\": \"palmyra-x-003-instruct\",\n \"prompt\": \"Write me an SEO article about...\"\n }'" + } + } }, { - name: 'list', - endpoint: '/v1/models', - httpMethod: 'get', - summary: 'List models', - description: - 'Retrieve a list of available models that can be used for text generation, chat completions, and other AI tasks.', - stainlessPath: '(resource) models > (method) list', - qualified: 'client.models.list', - response: '{ models: { id: string; name: string; }[]; }', - markdown: - "## list\n\n`client.models.list(): { models: object[]; }`\n\n**get** `/v1/models`\n\nRetrieve a list of available models that can be used for text generation, chat completions, and other AI tasks.\n\n### Returns\n\n- `{ models: { id: string; name: string; }[]; }`\n\n - `models: { id: string; name: string; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst models = await client.models.list();\n\nconsole.log(models);\n```", - perLanguage: { - typescript: { - method: 'client.models.list', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst models = await client.models.list();\n\nconsole.log(models.models);", - }, - python: { - method: 'models.list', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nmodels = client.models.list()\nprint(models.models)', - }, - go: { - method: 'client.Models.List', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tmodels, err := client.Models.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", models.Models)\n}\n', - }, - http: { - example: 'curl https://api.writer.com/v1/models \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "name": "list", + "endpoint": "/v1/models", + "httpMethod": "get", + "summary": "List models", + "description": "Retrieve a list of available models that can be used for text generation, chat completions, and other AI tasks.", + "stainlessPath": "(resource) models > (method) list", + "qualified": "client.models.list", + "response": "{ models: { id: string; name: string; }[]; }", + "markdown": "## list\n\n`client.models.list(): { models: object[]; }`\n\n**get** `/v1/models`\n\nRetrieve a list of available models that can be used for text generation, chat completions, and other AI tasks.\n\n### Returns\n\n- `{ models: { id: string; name: string; }[]; }`\n\n - `models: { id: string; name: string; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst models = await client.models.list();\n\nconsole.log(models);\n```", + "perLanguage": { + "typescript": { + "method": "client.models.list", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst models = await client.models.list();\n\nconsole.log(models.models);" + }, + "python": { + "method": "models.list", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nmodels = client.models.list()\nprint(models.models)" + }, + "go": { + "method": "client.Models.List", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tmodels, err := client.Models.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", models.Models)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/models \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'list', - endpoint: '/v1/graphs', - httpMethod: 'get', - summary: 'List graphs', - description: 'Retrieve a list of Knowledge Graphs.', - stainlessPath: '(resource) graphs > (method) list', - qualified: 'client.graphs.list', - params: ['after?: string;', 'before?: string;', 'limit?: number;', "order?: 'asc' | 'desc';"], - response: - "{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", - markdown: - "## list\n\n`client.graphs.list(after?: string, before?: string, limit?: number, order?: 'asc' | 'desc'): { id: string; created_at: string; file_status: object; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: object[]; }`\n\n**get** `/v1/graphs`\n\nRetrieve a list of Knowledge Graphs.\n\n### Parameters\n\n- `after?: string`\n The ID of the last object in the previous page. This parameter instructs the API to return the next page of results.\n\n- `before?: string`\n The ID of the first object in the previous page. This parameter instructs the API to return the previous page of results.\n\n- `limit?: number`\n Specifies the maximum number of objects returned in a page. The default value is 50. The minimum value is 1, and the maximum value is 100.\n\n- `order?: 'asc' | 'desc'`\n Specifies the order of the results. Valid values are asc for ascending and desc for descending.\n\n### Returns\n\n- `{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `file_status: { completed: number; failed: number; in_progress: number; total: number; }`\n - `name: string`\n - `type: 'manual' | 'connector' | 'web'`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const graph of client.graphs.list()) {\n console.log(graph);\n}\n```", - perLanguage: { - typescript: { - method: 'client.graphs.list', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const graph of client.graphs.list()) {\n console.log(graph.id);\n}", - }, - python: { - method: 'graphs.list', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\npage = client.graphs.list()\npage = page.data[0]\nprint(page.id)', - }, - go: { - method: 'client.Graphs.List', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Graphs.List(context.TODO(), writersdk.GraphListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', - }, - http: { - example: 'curl https://api.writer.com/v1/graphs \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "name": "list", + "endpoint": "/v1/graphs", + "httpMethod": "get", + "summary": "List graphs", + "description": "Retrieve a list of Knowledge Graphs.", + "stainlessPath": "(resource) graphs > (method) list", + "qualified": "client.graphs.list", + "params": [ + "after?: string;", + "before?: string;", + "limit?: number;", + "order?: 'asc' | 'desc';" + ], + "response": "{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", + "markdown": "## list\n\n`client.graphs.list(after?: string, before?: string, limit?: number, order?: 'asc' | 'desc'): { id: string; created_at: string; file_status: object; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: object[]; }`\n\n**get** `/v1/graphs`\n\nRetrieve a list of Knowledge Graphs.\n\n### Parameters\n\n- `after?: string`\n The ID of the last object in the previous page. This parameter instructs the API to return the next page of results.\n\n- `before?: string`\n The ID of the first object in the previous page. This parameter instructs the API to return the previous page of results.\n\n- `limit?: number`\n Specifies the maximum number of objects returned in a page. The default value is 50. The minimum value is 1, and the maximum value is 100.\n\n- `order?: 'asc' | 'desc'`\n Specifies the order of the results. Valid values are asc for ascending and desc for descending.\n\n### Returns\n\n- `{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `file_status: { completed: number; failed: number; in_progress: number; total: number; }`\n - `name: string`\n - `type: 'manual' | 'connector' | 'web'`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const graph of client.graphs.list()) {\n console.log(graph);\n}\n```", + "perLanguage": { + "typescript": { + "method": "client.graphs.list", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const graph of client.graphs.list()) {\n console.log(graph.id);\n}" + }, + "python": { + "method": "graphs.list", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\npage = client.graphs.list()\npage = page.data[0]\nprint(page.id)" + }, + "go": { + "method": "client.Graphs.List", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tpage, err := client.Graphs.List(context.TODO(), writersdk.GraphListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", page)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/graphs \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'create', - endpoint: '/v1/graphs', - httpMethod: 'post', - summary: 'Create graph', - description: 'Create a new Knowledge Graph.', - stainlessPath: '(resource) graphs > (method) create', - qualified: 'client.graphs.create', - params: ['description?: string;', 'name?: string;'], - response: - "{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", - markdown: - "## create\n\n`client.graphs.create(description?: string, name?: string): { id: string; created_at: string; name: string; description?: string; urls?: object[]; }`\n\n**post** `/v1/graphs`\n\nCreate a new Knowledge Graph.\n\n### Parameters\n\n- `description?: string`\n A description of the Knowledge Graph (max 255 characters). Omitting this field leaves the description unchanged.\n\n- `name?: string`\n The name of the Knowledge Graph (max 255 characters). Omitting this field leaves the name unchanged.\n\n### Returns\n\n- `{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `name: string`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.create();\n\nconsole.log(graph);\n```", - perLanguage: { - typescript: { - method: 'client.graphs.create', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.create();\n\nconsole.log(graph.id);", - }, - python: { - method: 'graphs.create', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ngraph = client.graphs.create()\nprint(graph.id)', - }, - go: { - method: 'client.Graphs.New', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.New(context.TODO(), writersdk.GraphNewParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', - }, - http: { - example: - "curl https://api.writer.com/v1/graphs \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'", - }, - }, + "name": "create", + "endpoint": "/v1/graphs", + "httpMethod": "post", + "summary": "Create graph", + "description": "Create a new Knowledge Graph.", + "stainlessPath": "(resource) graphs > (method) create", + "qualified": "client.graphs.create", + "params": [ + "description?: string;", + "name?: string;" + ], + "response": "{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", + "markdown": "## create\n\n`client.graphs.create(description?: string, name?: string): { id: string; created_at: string; name: string; description?: string; urls?: object[]; }`\n\n**post** `/v1/graphs`\n\nCreate a new Knowledge Graph.\n\n### Parameters\n\n- `description?: string`\n A description of the Knowledge Graph (max 255 characters). Omitting this field leaves the description unchanged.\n\n- `name?: string`\n The name of the Knowledge Graph (max 255 characters). Omitting this field leaves the name unchanged.\n\n### Returns\n\n- `{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `name: string`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.create();\n\nconsole.log(graph);\n```", + "perLanguage": { + "typescript": { + "method": "client.graphs.create", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.create();\n\nconsole.log(graph.id);" + }, + "python": { + "method": "graphs.create", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\ngraph = client.graphs.create()\nprint(graph.id)" + }, + "go": { + "method": "client.Graphs.New", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tgraph, err := client.Graphs.New(context.TODO(), writersdk.GraphNewParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", graph.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/graphs \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'" + } + } }, { - name: 'retrieve', - endpoint: '/v1/graphs/{graph_id}', - httpMethod: 'get', - summary: 'Retrieve graph', - description: 'Retrieve a Knowledge Graph.', - stainlessPath: '(resource) graphs > (method) retrieve', - qualified: 'client.graphs.retrieve', - params: ['graph_id: string;'], - response: - "{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", - markdown: - "## retrieve\n\n`client.graphs.retrieve(graph_id: string): { id: string; created_at: string; file_status: object; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: object[]; }`\n\n**get** `/v1/graphs/{graph_id}`\n\nRetrieve a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `file_status: { completed: number; failed: number; in_progress: number; total: number; }`\n - `name: string`\n - `type: 'manual' | 'connector' | 'web'`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", - perLanguage: { - typescript: { - method: 'client.graphs.retrieve', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);", - }, - python: { - method: 'graphs.retrieve', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ngraph = client.graphs.retrieve(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(graph.id)', - }, - go: { - method: 'client.Graphs.Get', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.Get(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "name": "retrieve", + "endpoint": "/v1/graphs/{graph_id}", + "httpMethod": "get", + "summary": "Retrieve graph", + "description": "Retrieve a Knowledge Graph.", + "stainlessPath": "(resource) graphs > (method) retrieve", + "qualified": "client.graphs.retrieve", + "params": [ + "graph_id: string;" + ], + "response": "{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", + "markdown": "## retrieve\n\n`client.graphs.retrieve(graph_id: string): { id: string; created_at: string; file_status: object; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: object[]; }`\n\n**get** `/v1/graphs/{graph_id}`\n\nRetrieve a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `file_status: { completed: number; failed: number; in_progress: number; total: number; }`\n - `name: string`\n - `type: 'manual' | 'connector' | 'web'`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", + "perLanguage": { + "typescript": { + "method": "client.graphs.retrieve", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);" + }, + "python": { + "method": "graphs.retrieve", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\ngraph = client.graphs.retrieve(\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n)\nprint(graph.id)" + }, + "go": { + "method": "client.Graphs.Get", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tgraph, err := client.Graphs.Get(context.TODO(), \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", graph.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'update', - endpoint: '/v1/graphs/{graph_id}', - httpMethod: 'put', - summary: 'Update graph', - description: 'Update the name and description of a Knowledge Graph.', - stainlessPath: '(resource) graphs > (method) update', - qualified: 'client.graphs.update', - params: [ - 'graph_id: string;', - 'description?: string;', - 'name?: string;', - "urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[];", + "name": "update", + "endpoint": "/v1/graphs/{graph_id}", + "httpMethod": "put", + "summary": "Update graph", + "description": "Update the name and description of a Knowledge Graph.", + "stainlessPath": "(resource) graphs > (method) update", + "qualified": "client.graphs.update", + "params": [ + "graph_id: string;", + "description?: string;", + "name?: string;", + "urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[];" ], - response: - "{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", - markdown: - "## update\n\n`client.graphs.update(graph_id: string, description?: string, name?: string, urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]): { id: string; created_at: string; name: string; description?: string; urls?: object[]; }`\n\n**put** `/v1/graphs/{graph_id}`\n\nUpdate the name and description of a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `description?: string`\n A description of the Knowledge Graph (max 255 characters). Omitting this field leaves the description unchanged.\n\n- `name?: string`\n The name of the Knowledge Graph (max 255 characters). Omitting this field leaves the name unchanged.\n\n- `urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n An array of web connector URLs to update for this Knowledge Graph. You can only connect URLs to Knowledge Graphs with the type `web`. To clear the list of URLs, set this field to an empty array.\n\n### Returns\n\n- `{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `name: string`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.update('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", - perLanguage: { - typescript: { - method: 'client.graphs.update', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.update('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);", - }, - python: { - method: 'graphs.update', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ngraph = client.graphs.update(\n graph_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(graph.id)', - }, - go: { - method: 'client.Graphs.Update', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.Update(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\twritersdk.GraphUpdateParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', - }, - http: { - example: - "curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -X PUT \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'", - }, - }, + "response": "{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", + "markdown": "## update\n\n`client.graphs.update(graph_id: string, description?: string, name?: string, urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]): { id: string; created_at: string; name: string; description?: string; urls?: object[]; }`\n\n**put** `/v1/graphs/{graph_id}`\n\nUpdate the name and description of a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `description?: string`\n A description of the Knowledge Graph (max 255 characters). Omitting this field leaves the description unchanged.\n\n- `name?: string`\n The name of the Knowledge Graph (max 255 characters). Omitting this field leaves the name unchanged.\n\n- `urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n An array of web connector URLs to update for this Knowledge Graph. You can only connect URLs to Knowledge Graphs with the type `web`. To clear the list of URLs, set this field to an empty array.\n\n### Returns\n\n- `{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `name: string`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.update('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", + "perLanguage": { + "typescript": { + "method": "client.graphs.update", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.update('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);" + }, + "python": { + "method": "graphs.update", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\ngraph = client.graphs.update(\n graph_id=\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n)\nprint(graph.id)" + }, + "go": { + "method": "client.Graphs.Update", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tgraph, err := client.Graphs.Update(\n\t\tcontext.TODO(),\n\t\t\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n\t\twritersdk.GraphUpdateParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", graph.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -X PUT \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'" + } + } }, { - name: 'delete', - endpoint: '/v1/graphs/{graph_id}', - httpMethod: 'delete', - summary: 'Delete graph', - description: 'Delete a Knowledge Graph.', - stainlessPath: '(resource) graphs > (method) delete', - qualified: 'client.graphs.delete', - params: ['graph_id: string;'], - response: '{ id: string; deleted: boolean; }', - markdown: - "## delete\n\n`client.graphs.delete(graph_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/graphs/{graph_id}`\n\nDelete a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.delete('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", - perLanguage: { - typescript: { - method: 'client.graphs.delete', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.delete('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);", - }, - python: { - method: 'graphs.delete', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ngraph = client.graphs.delete(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(graph.id)', - }, - go: { - method: 'client.Graphs.Delete', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.Delete(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -X DELETE \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "name": "delete", + "endpoint": "/v1/graphs/{graph_id}", + "httpMethod": "delete", + "summary": "Delete graph", + "description": "Delete a Knowledge Graph.", + "stainlessPath": "(resource) graphs > (method) delete", + "qualified": "client.graphs.delete", + "params": [ + "graph_id: string;" + ], + "response": "{ id: string; deleted: boolean; }", + "markdown": "## delete\n\n`client.graphs.delete(graph_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/graphs/{graph_id}`\n\nDelete a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.delete('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", + "perLanguage": { + "typescript": { + "method": "client.graphs.delete", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.delete('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);" + }, + "python": { + "method": "graphs.delete", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\ngraph = client.graphs.delete(\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n)\nprint(graph.id)" + }, + "go": { + "method": "client.Graphs.Delete", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tgraph, err := client.Graphs.Delete(context.TODO(), \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", graph.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -X DELETE \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'add_file_to_graph', - endpoint: '/v1/graphs/{graph_id}/file', - httpMethod: 'post', - summary: 'Add file to graph', - description: 'Add a file to a Knowledge Graph.', - stainlessPath: '(resource) graphs > (method) add_file_to_graph', - qualified: 'client.graphs.addFileToGraph', - params: ['graph_id: string;', 'file_id: string;'], - response: '{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }', - markdown: - "## add_file_to_graph\n\n`client.graphs.addFileToGraph(graph_id: string, file_id: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**post** `/v1/graphs/{graph_id}/file`\n\nAdd a file to a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `file_id: string`\n The unique identifier of the file.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { file_id: 'file_id' });\n\nconsole.log(file);\n```", - perLanguage: { - typescript: { - method: 'client.graphs.addFileToGraph', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', {\n file_id: 'file_id',\n});\n\nconsole.log(file.id);", - }, - python: { - method: 'graphs.add_file_to_graph', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfile = client.graphs.add_file_to_graph(\n graph_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n file_id="file_id",\n)\nprint(file.id)', - }, - go: { - method: 'client.Graphs.AddFileToGraph', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Graphs.AddFileToGraph(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\twritersdk.GraphAddFileToGraphParams{\n\t\t\tFileID: writersdk.F("file_id"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/graphs/$GRAPH_ID/file \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "file_id": "file_id"\n }\'', - }, - }, + "name": "add_file_to_graph", + "endpoint": "/v1/graphs/{graph_id}/file", + "httpMethod": "post", + "summary": "Add file to graph", + "description": "Add a file to a Knowledge Graph.", + "stainlessPath": "(resource) graphs > (method) add_file_to_graph", + "qualified": "client.graphs.addFileToGraph", + "params": [ + "graph_id: string;", + "file_id: string;" + ], + "response": "{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }", + "markdown": "## add_file_to_graph\n\n`client.graphs.addFileToGraph(graph_id: string, file_id: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**post** `/v1/graphs/{graph_id}/file`\n\nAdd a file to a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `file_id: string`\n The unique identifier of the file.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { file_id: 'file_id' });\n\nconsole.log(file);\n```", + "perLanguage": { + "typescript": { + "method": "client.graphs.addFileToGraph", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', {\n file_id: 'file_id',\n});\n\nconsole.log(file.id);" + }, + "python": { + "method": "graphs.add_file_to_graph", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfile = client.graphs.add_file_to_graph(\n graph_id=\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n file_id=\"file_id\",\n)\nprint(file.id)" + }, + "go": { + "method": "client.Graphs.AddFileToGraph", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tfile, err := client.Graphs.AddFileToGraph(\n\t\tcontext.TODO(),\n\t\t\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n\t\twritersdk.GraphAddFileToGraphParams{\n\t\t\tFileID: writersdk.F(\"file_id\"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", file.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/graphs/$GRAPH_ID/file \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"file_id\": \"file_id\"\n }'" + } + } }, { - name: 'remove_file_from_graph', - endpoint: '/v1/graphs/{graph_id}/file/{file_id}', - httpMethod: 'delete', - summary: 'Remove file from graph', - description: 'Remove a file from a Knowledge Graph.', - stainlessPath: '(resource) graphs > (method) remove_file_from_graph', - qualified: 'client.graphs.removeFileFromGraph', - params: ['graph_id: string;', 'file_id: string;'], - response: '{ id: string; deleted: boolean; }', - markdown: - "## remove_file_from_graph\n\n`client.graphs.removeFileFromGraph(graph_id: string, file_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/graphs/{graph_id}/file/{file_id}`\n\nRemove a file from a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.graphs.removeFileFromGraph('file_id', { graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e' });\n\nconsole.log(response);\n```", - perLanguage: { - typescript: { - method: 'client.graphs.removeFileFromGraph', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.graphs.removeFileFromGraph('file_id', {\n graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n});\n\nconsole.log(response.id);", - }, - python: { - method: 'graphs.remove_file_from_graph', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.graphs.remove_file_from_graph(\n file_id="file_id",\n graph_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(response.id)', - }, - go: { - method: 'client.Graphs.RemoveFileFromGraph', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Graphs.RemoveFileFromGraph(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\t"file_id",\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.ID)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/graphs/$GRAPH_ID/file/$FILE_ID \\\n -X DELETE \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "name": "remove_file_from_graph", + "endpoint": "/v1/graphs/{graph_id}/file/{file_id}", + "httpMethod": "delete", + "summary": "Remove file from graph", + "description": "Remove a file from a Knowledge Graph.", + "stainlessPath": "(resource) graphs > (method) remove_file_from_graph", + "qualified": "client.graphs.removeFileFromGraph", + "params": [ + "graph_id: string;", + "file_id: string;" + ], + "response": "{ id: string; deleted: boolean; }", + "markdown": "## remove_file_from_graph\n\n`client.graphs.removeFileFromGraph(graph_id: string, file_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/graphs/{graph_id}/file/{file_id}`\n\nRemove a file from a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.graphs.removeFileFromGraph('file_id', { graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e' });\n\nconsole.log(response);\n```", + "perLanguage": { + "typescript": { + "method": "client.graphs.removeFileFromGraph", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.graphs.removeFileFromGraph('file_id', {\n graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n});\n\nconsole.log(response.id);" + }, + "python": { + "method": "graphs.remove_file_from_graph", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nresponse = client.graphs.remove_file_from_graph(\n file_id=\"file_id\",\n graph_id=\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n)\nprint(response.id)" + }, + "go": { + "method": "client.Graphs.RemoveFileFromGraph", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tresponse, err := client.Graphs.RemoveFileFromGraph(\n\t\tcontext.TODO(),\n\t\t\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n\t\t\"file_id\",\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", response.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/graphs/$GRAPH_ID/file/$FILE_ID \\\n -X DELETE \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'question', - endpoint: '/v1/graphs/question', - httpMethod: 'post', - summary: 'Question', - description: 'Ask a question to specified Knowledge Graphs.', - stainlessPath: '(resource) graphs > (method) question', - qualified: 'client.graphs.question', - params: [ - 'graph_ids: string[];', - 'question: string;', - 'query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; };', - 'stream?: boolean;', - 'subqueries?: boolean;', + "name": "question", + "endpoint": "/v1/graphs/question", + "httpMethod": "post", + "summary": "Question", + "description": "Ask a question to specified Knowledge Graphs.", + "stainlessPath": "(resource) graphs > (method) question", + "qualified": "client.graphs.question", + "params": [ + "graph_ids: string[];", + "question: string;", + "query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; };", + "stream?: boolean;", + "subqueries?: boolean;" ], - response: - '{ answer: string; question: string; sources: { file_id: string; snippet: string; }[]; references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }; subqueries?: { answer: string; query: string; sources: object[]; }[]; }', - markdown: - "## question\n\n`client.graphs.question(graph_ids: string[], question: string, query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }, stream?: boolean, subqueries?: boolean): { answer: string; question: string; sources: source[]; references?: object; subqueries?: object[]; }`\n\n**post** `/v1/graphs/question`\n\nAsk a question to specified Knowledge Graphs.\n\n### Parameters\n\n- `graph_ids: string[]`\n The unique identifiers of the Knowledge Graphs to query.\n\n- `question: string`\n The question to answer using the Knowledge Graph.\n\n- `query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }`\n Configuration options for Knowledge Graph queries, including search parameters and citation settings.\n - `grounding_level?: number`\n Level of grounding required for responses, controlling how closely answers must be tied to source material. Set lower for grounded outputs, higher for creativity. Higher values (closer to 1.0) allow more creative interpretation, while lower values (closer to 0.0) stick more closely to source material. Range: 0.0-1.0, Default: 0.0.\n - `inline_citations?: boolean`\n Whether to include inline citations in the response, showing which Knowledge Graph sources were used. Default: false.\n - `keyword_threshold?: number`\n Threshold for keyword-based matching when searching Knowledge Graph content. Set higher for stricter relevance, lower for broader range. Higher values (closer to 1.0) require stronger keyword matches, while lower values (closer to 0.0) allow more lenient matching. Range: 0.0-1.0, Default: 0.7.\n - `max_snippets?: number`\n Maximum number of text snippets to retrieve from the Knowledge Graph for context. Works in concert with `search_weight` to control best matches vs broader coverage. While technically supports 1-60, values below 5 may return no results due to RAG implementation. Recommended range: 5-25. Due to RAG system behavior, you may see more snippets than requested. Range: 1-60, Default: 30.\n - `max_subquestions?: number`\n Maximum number of subquestions to generate when processing complex queries. Set higher to improve detail, set lower to reduce response time. Range: 1-10, Default: 6.\n - `max_tokens?: number`\n Maximum number of tokens the model can generate in the response. This controls the length of the AI's answer. Set higher for longer answers, set lower for shorter, faster answers. Range: 100-8000, Default: 4000.\n - `search_weight?: number`\n Weight given to search results when ranking and selecting relevant information. Higher values (closer to 100) prioritize keyword-based matching, while lower values (closer to 0) prioritize semantic similarity matching. Use higher values for exact keyword searches, lower values for conceptual similarity searches. Range: 0-100, Default: 50.\n - `semantic_threshold?: number`\n Threshold for semantic similarity matching when searching Knowledge Graph content. Set higher for stricter relevance, lower for broader range. Higher values (closer to 1.0) require stronger semantic similarity, while lower values (closer to 0.0) allow more lenient semantic matching. Range: 0.0-1.0, Default: 0.7.\n\n- `stream?: boolean`\n Determines whether the model's output should be streamed. If true, the output is generated and sent incrementally, which can be useful for real-time applications.\n\n- `subqueries?: boolean`\n Specify whether to include subqueries.\n\n### Returns\n\n- `{ answer: string; question: string; sources: { file_id: string; snippet: string; }[]; references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }; subqueries?: { answer: string; query: string; sources: object[]; }[]; }`\n\n - `answer: string`\n - `question: string`\n - `sources: { file_id: string; snippet: string; }[]`\n - `references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }`\n - `subqueries?: { answer: string; query: string; sources: { file_id: string; snippet: string; }[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.graphs.question({ graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], question: 'question' });\nfor await (const questionResponseChunk of stream) {\n console.log(questionResponseChunk);\n}\n```", - perLanguage: { - typescript: { - method: 'client.graphs.question', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst question = await client.graphs.question({\n graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'],\n question: 'question',\n});\n\nconsole.log(question.answer);", - }, - python: { - method: 'graphs.question', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfor graph in client.graphs.question(\n graph_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],\n question="question",\n):\n print(graph)', - }, - go: { - method: 'client.Graphs.Question', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tquestion, err := client.Graphs.Question(context.TODO(), writersdk.GraphQuestionParams{\n\t\tGraphIDs: writersdk.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}),\n\t\tQuestion: writersdk.F("question"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", question.Answer)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/graphs/question \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "graph_ids": [\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"\n ],\n "question": "question"\n }\'', - }, - }, + "response": "{ answer: string; question: string; sources: { file_id: string; snippet: string; }[]; references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }; subqueries?: { answer: string; query: string; sources: object[]; }[]; }", + "markdown": "## question\n\n`client.graphs.question(graph_ids: string[], question: string, query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }, stream?: boolean, subqueries?: boolean): { answer: string; question: string; sources: source[]; references?: object; subqueries?: object[]; }`\n\n**post** `/v1/graphs/question`\n\nAsk a question to specified Knowledge Graphs.\n\n### Parameters\n\n- `graph_ids: string[]`\n The unique identifiers of the Knowledge Graphs to query.\n\n- `question: string`\n The question to answer using the Knowledge Graph.\n\n- `query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }`\n Configuration options for Knowledge Graph queries, including search parameters and citation settings.\n - `grounding_level?: number`\n Level of grounding required for responses, controlling how closely answers must be tied to source material. Set lower for grounded outputs, higher for creativity. Higher values (closer to 1.0) allow more creative interpretation, while lower values (closer to 0.0) stick more closely to source material. Range: 0.0-1.0, Default: 0.0.\n - `inline_citations?: boolean`\n Whether to include inline citations in the response, showing which Knowledge Graph sources were used. Default: false.\n - `keyword_threshold?: number`\n Threshold for keyword-based matching when searching Knowledge Graph content. Set higher for stricter relevance, lower for broader range. Higher values (closer to 1.0) require stronger keyword matches, while lower values (closer to 0.0) allow more lenient matching. Range: 0.0-1.0, Default: 0.7.\n - `max_snippets?: number`\n Maximum number of text snippets to retrieve from the Knowledge Graph for context. Works in concert with `search_weight` to control best matches vs broader coverage. While technically supports 1-60, values below 5 may return no results due to RAG implementation. Recommended range: 5-25. Due to RAG system behavior, you may see more snippets than requested. Range: 1-60, Default: 30.\n - `max_subquestions?: number`\n Maximum number of subquestions to generate when processing complex queries. Set higher to improve detail, set lower to reduce response time. Range: 1-10, Default: 6.\n - `max_tokens?: number`\n Maximum number of tokens the model can generate in the response. This controls the length of the AI's answer. Set higher for longer answers, set lower for shorter, faster answers. Range: 100-8000, Default: 4000.\n - `search_weight?: number`\n Weight given to search results when ranking and selecting relevant information. Higher values (closer to 100) prioritize keyword-based matching, while lower values (closer to 0) prioritize semantic similarity matching. Use higher values for exact keyword searches, lower values for conceptual similarity searches. Range: 0-100, Default: 50.\n - `semantic_threshold?: number`\n Threshold for semantic similarity matching when searching Knowledge Graph content. Set higher for stricter relevance, lower for broader range. Higher values (closer to 1.0) require stronger semantic similarity, while lower values (closer to 0.0) allow more lenient semantic matching. Range: 0.0-1.0, Default: 0.7.\n\n- `stream?: boolean`\n Determines whether the model's output should be streamed. If true, the output is generated and sent incrementally, which can be useful for real-time applications.\n\n- `subqueries?: boolean`\n Specify whether to include subqueries.\n\n### Returns\n\n- `{ answer: string; question: string; sources: { file_id: string; snippet: string; }[]; references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }; subqueries?: { answer: string; query: string; sources: object[]; }[]; }`\n\n - `answer: string`\n - `question: string`\n - `sources: { file_id: string; snippet: string; }[]`\n - `references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }`\n - `subqueries?: { answer: string; query: string; sources: { file_id: string; snippet: string; }[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.graphs.question({ graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], question: 'question' });\nfor await (const questionResponseChunk of stream) {\n console.log(questionResponseChunk);\n}\n```", + "perLanguage": { + "typescript": { + "method": "client.graphs.question", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst question = await client.graphs.question({\n graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'],\n question: 'question',\n});\n\nconsole.log(question.answer);" + }, + "python": { + "method": "graphs.question", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfor graph in client.graphs.question(\n graph_ids=[\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"],\n question=\"question\",\n):\n print(graph)" + }, + "go": { + "method": "client.Graphs.Question", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tquestion, err := client.Graphs.Question(context.TODO(), writersdk.GraphQuestionParams{\n\t\tGraphIDs: writersdk.F([]string{\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"}),\n\t\tQuestion: writersdk.F(\"question\"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", question.Answer)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/graphs/question \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"graph_ids\": [\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"\n ],\n \"question\": \"question\"\n }'" + } + } }, { - name: 'retrieve', - endpoint: '/v1/files/{file_id}', - httpMethod: 'get', - summary: 'Retrieve file', - description: - 'Retrieve detailed information about a specific file, including its metadata, status, and associated graphs.', - stainlessPath: '(resource) files > (method) retrieve', - qualified: 'client.files.retrieve', - params: ['file_id: string;'], - response: '{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }', - markdown: - "## retrieve\n\n`client.files.retrieve(file_id: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**get** `/v1/files/{file_id}`\n\nRetrieve detailed information about a specific file, including its metadata, status, and associated graphs.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.retrieve('file_id');\n\nconsole.log(file);\n```", - perLanguage: { - typescript: { - method: 'client.files.retrieve', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.retrieve('file_id');\n\nconsole.log(file.id);", - }, - python: { - method: 'files.retrieve', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfile = client.files.retrieve(\n "file_id",\n)\nprint(file.id)', - }, - go: { - method: 'client.Files.Get', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Get(context.TODO(), "file_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/files/$FILE_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "name": "retrieve", + "endpoint": "/v1/files/{file_id}", + "httpMethod": "get", + "summary": "Retrieve file", + "description": "Retrieve detailed information about a specific file, including its metadata, status, and associated graphs.", + "stainlessPath": "(resource) files > (method) retrieve", + "qualified": "client.files.retrieve", + "params": [ + "file_id: string;" + ], + "response": "{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }", + "markdown": "## retrieve\n\n`client.files.retrieve(file_id: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**get** `/v1/files/{file_id}`\n\nRetrieve detailed information about a specific file, including its metadata, status, and associated graphs.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.retrieve('file_id');\n\nconsole.log(file);\n```", + "perLanguage": { + "typescript": { + "method": "client.files.retrieve", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.retrieve('file_id');\n\nconsole.log(file.id);" + }, + "python": { + "method": "files.retrieve", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfile = client.files.retrieve(\n \"file_id\",\n)\nprint(file.id)" + }, + "go": { + "method": "client.Files.Get", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tfile, err := client.Files.Get(context.TODO(), \"file_id\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", file.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/files/$FILE_ID \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'delete', - endpoint: '/v1/files/{file_id}', - httpMethod: 'delete', - summary: 'Delete file', - description: 'Permanently delete a file from the system. This action cannot be undone.', - stainlessPath: '(resource) files > (method) delete', - qualified: 'client.files.delete', - params: ['file_id: string;'], - response: '{ id: string; deleted: boolean; }', - markdown: - "## delete\n\n`client.files.delete(file_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/files/{file_id}`\n\nPermanently delete a file from the system. This action cannot be undone.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.delete('file_id');\n\nconsole.log(file);\n```", - perLanguage: { - typescript: { - method: 'client.files.delete', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.delete('file_id');\n\nconsole.log(file.id);", - }, - python: { - method: 'files.delete', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfile = client.files.delete(\n "file_id",\n)\nprint(file.id)', - }, - go: { - method: 'client.Files.Delete', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Delete(context.TODO(), "file_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/files/$FILE_ID \\\n -X DELETE \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "name": "delete", + "endpoint": "/v1/files/{file_id}", + "httpMethod": "delete", + "summary": "Delete file", + "description": "Permanently delete a file from the system. This action cannot be undone.", + "stainlessPath": "(resource) files > (method) delete", + "qualified": "client.files.delete", + "params": [ + "file_id: string;" + ], + "response": "{ id: string; deleted: boolean; }", + "markdown": "## delete\n\n`client.files.delete(file_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/files/{file_id}`\n\nPermanently delete a file from the system. This action cannot be undone.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.delete('file_id');\n\nconsole.log(file);\n```", + "perLanguage": { + "typescript": { + "method": "client.files.delete", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.delete('file_id');\n\nconsole.log(file.id);" + }, + "python": { + "method": "files.delete", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfile = client.files.delete(\n \"file_id\",\n)\nprint(file.id)" + }, + "go": { + "method": "client.Files.Delete", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tfile, err := client.Files.Delete(context.TODO(), \"file_id\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", file.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/files/$FILE_ID \\\n -X DELETE \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'list', - endpoint: '/v1/files', - httpMethod: 'get', - summary: 'List files', - description: - 'Retrieve a paginated list of files with optional filtering by status, graph association, and file type.', - stainlessPath: '(resource) files > (method) list', - qualified: 'client.files.list', - params: [ - 'after?: string;', - 'before?: string;', - 'file_types?: string;', - 'graph_id?: string;', - 'limit?: number;', + "name": "list", + "endpoint": "/v1/files", + "httpMethod": "get", + "summary": "List files", + "description": "Retrieve a paginated list of files with optional filtering by status, graph association, and file type.", + "stainlessPath": "(resource) files > (method) list", + "qualified": "client.files.list", + "params": [ + "after?: string;", + "before?: string;", + "file_types?: string;", + "graph_id?: string;", + "limit?: number;", "order?: 'asc' | 'desc';", - "status?: 'in_progress' | 'completed' | 'failed';", + "status?: 'in_progress' | 'completed' | 'failed';" ], - response: '{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }', - markdown: - "## list\n\n`client.files.list(after?: string, before?: string, file_types?: string, graph_id?: string, limit?: number, order?: 'asc' | 'desc', status?: 'in_progress' | 'completed' | 'failed'): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**get** `/v1/files`\n\nRetrieve a paginated list of files with optional filtering by status, graph association, and file type.\n\n### Parameters\n\n- `after?: string`\n The ID of the last object in the previous page. This parameter instructs the API to return the next page of results.\n\n- `before?: string`\n The ID of the first object in the previous page. This parameter instructs the API to return the previous page of results.\n\n- `file_types?: string`\n The extensions of the files to retrieve. Separate multiple extensions with a comma. For example: `pdf,jpg,docx`.\n\n- `graph_id?: string`\n The unique identifier of the graph to which the files belong.\n\n- `limit?: number`\n Specifies the maximum number of objects returned in a page. The default value is 50. The minimum value is 1, and the maximum value is 100.\n\n- `order?: 'asc' | 'desc'`\n Specifies the order of the results. Valid values are asc for ascending and desc for descending.\n\n- `status?: 'in_progress' | 'completed' | 'failed'`\n Specifies the status of the files to retrieve. Valid values are in_progress, completed or failed.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const file of client.files.list()) {\n console.log(file);\n}\n```", - perLanguage: { - typescript: { - method: 'client.files.list', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const file of client.files.list()) {\n console.log(file.id);\n}", - }, - python: { - method: 'files.list', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\npage = client.files.list()\npage = page.data[0]\nprint(page.id)', - }, - go: { - method: 'client.Files.List', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Files.List(context.TODO(), writersdk.FileListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', - }, - http: { - example: 'curl https://api.writer.com/v1/files \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "response": "{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }", + "markdown": "## list\n\n`client.files.list(after?: string, before?: string, file_types?: string, graph_id?: string, limit?: number, order?: 'asc' | 'desc', status?: 'in_progress' | 'completed' | 'failed'): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**get** `/v1/files`\n\nRetrieve a paginated list of files with optional filtering by status, graph association, and file type.\n\n### Parameters\n\n- `after?: string`\n The ID of the last object in the previous page. This parameter instructs the API to return the next page of results.\n\n- `before?: string`\n The ID of the first object in the previous page. This parameter instructs the API to return the previous page of results.\n\n- `file_types?: string`\n The extensions of the files to retrieve. Separate multiple extensions with a comma. For example: `pdf,jpg,docx`.\n\n- `graph_id?: string`\n The unique identifier of the graph to which the files belong.\n\n- `limit?: number`\n Specifies the maximum number of objects returned in a page. The default value is 50. The minimum value is 1, and the maximum value is 100.\n\n- `order?: 'asc' | 'desc'`\n Specifies the order of the results. Valid values are asc for ascending and desc for descending.\n\n- `status?: 'in_progress' | 'completed' | 'failed'`\n Specifies the status of the files to retrieve. Valid values are in_progress, completed or failed.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const file of client.files.list()) {\n console.log(file);\n}\n```", + "perLanguage": { + "typescript": { + "method": "client.files.list", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const file of client.files.list()) {\n console.log(file.id);\n}" + }, + "python": { + "method": "files.list", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\npage = client.files.list()\npage = page.data[0]\nprint(page.id)" + }, + "go": { + "method": "client.Files.List", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tpage, err := client.Files.List(context.TODO(), writersdk.FileListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", page)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/files \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'upload', - endpoint: '/v1/files', - httpMethod: 'post', - summary: 'Upload file', - description: - 'Upload a new file to the system. Supports various file formats including PDF, DOC, DOCX, PPT, PPTX, JPG, PNG, EML, HTML, SRT, CSV, XLS, and XLSX.', - stainlessPath: '(resource) files > (method) upload', - qualified: 'client.files.upload', - params: ['content: string;', 'Content-Disposition: string;', 'graphId?: string;'], - response: '{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }', - markdown: - "## upload\n\n`client.files.upload(content: string, Content-Disposition: string, graphId?: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**post** `/v1/files`\n\nUpload a new file to the system. Supports various file formats including PDF, DOC, DOCX, PPT, PPTX, JPG, PNG, EML, HTML, SRT, CSV, XLS, and XLSX.\n\n### Parameters\n\n- `content: string`\n\n- `Content-Disposition: string`\n\n- `graphId?: string`\n The unique identifier of the Knowledge Graph to associate the uploaded file with.\n\nNote: The response from the upload endpoint does not include the `graphId` field, but the association will be visible when you retrieve the file using the file retrieval endpoint.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.upload({ content: fs.createReadStream('path/to/file'), 'Content-Disposition': 'Content-Disposition' });\n\nconsole.log(file);\n```", - perLanguage: { - typescript: { - method: 'client.files.upload', - example: - "import fs from 'fs';\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.upload({\n content: fs.createReadStream('path/to/file'),\n 'Content-Disposition': 'Content-Disposition',\n});\n\nconsole.log(file.id);", - }, - python: { - method: 'files.upload', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfile = client.files.upload(\n content=b"Example data",\n content_disposition="Content-Disposition",\n)\nprint(file.id)', - }, - go: { - method: 'client.Files.Upload', - example: - 'package main\n\nimport (\n\t"bytes"\n\t"context"\n\t"fmt"\n\t"io"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Upload(context.TODO(), writersdk.FileUploadParams{\n\t\tContent: io.Reader(bytes.NewBuffer([]byte("Example data"))),\n\t\tContentDisposition: writersdk.F("Content-Disposition"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', - }, - http: { - example: - "curl https://api.writer.com/v1/files \\\n -H 'Content-Type: text/plain' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -F 'content=@/path/to/content'", - }, - }, + "name": "upload", + "endpoint": "/v1/files", + "httpMethod": "post", + "summary": "Upload file", + "description": "Upload a new file to the system. Supports various file formats including PDF, DOC, DOCX, PPT, PPTX, JPG, PNG, EML, HTML, SRT, CSV, XLS, and XLSX.", + "stainlessPath": "(resource) files > (method) upload", + "qualified": "client.files.upload", + "params": [ + "content: string;", + "Content-Disposition: string;", + "graphId?: string;" + ], + "response": "{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }", + "markdown": "## upload\n\n`client.files.upload(content: string, Content-Disposition: string, graphId?: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**post** `/v1/files`\n\nUpload a new file to the system. Supports various file formats including PDF, DOC, DOCX, PPT, PPTX, JPG, PNG, EML, HTML, SRT, CSV, XLS, and XLSX.\n\n### Parameters\n\n- `content: string`\n\n- `Content-Disposition: string`\n\n- `graphId?: string`\n The unique identifier of the Knowledge Graph to associate the uploaded file with.\n\nNote: The response from the upload endpoint does not include the `graphId` field, but the association will be visible when you retrieve the file using the file retrieval endpoint.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.upload({ content: fs.createReadStream('path/to/file'), 'Content-Disposition': 'Content-Disposition' });\n\nconsole.log(file);\n```", + "perLanguage": { + "typescript": { + "method": "client.files.upload", + "example": "import fs from 'fs';\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.upload({\n content: fs.createReadStream('path/to/file'),\n 'Content-Disposition': 'Content-Disposition',\n});\n\nconsole.log(file.id);" + }, + "python": { + "method": "files.upload", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfile = client.files.upload(\n content=b\"Example data\",\n content_disposition=\"Content-Disposition\",\n)\nprint(file.id)" + }, + "go": { + "method": "client.Files.Upload", + "example": "package main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tfile, err := client.Files.Upload(context.TODO(), writersdk.FileUploadParams{\n\t\tContent: io.Reader(bytes.NewBuffer([]byte(\"Example data\"))),\n\t\tContentDisposition: writersdk.F(\"Content-Disposition\"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", file.ID)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/files \\\n -H 'Content-Type: text/plain' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -F 'content=@/path/to/content'" + } + } }, { - name: 'download', - endpoint: '/v1/files/{file_id}/download', - httpMethod: 'get', - summary: 'Download file', - description: - 'Download the binary content of a file. The response will contain the file data in the appropriate MIME type.', - stainlessPath: '(resource) files > (method) download', - qualified: 'client.files.download', - params: ['file_id: string;'], - response: 'string', - markdown: - "## download\n\n`client.files.download(file_id: string): string`\n\n**get** `/v1/files/{file_id}/download`\n\nDownload the binary content of a file. The response will contain the file data in the appropriate MIME type.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.files.download('file_id');\n\nconsole.log(response);\n\nconst content = await response.blob()\nconsole.log(content)\n```", - perLanguage: { - typescript: { - method: 'client.files.download', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.files.download('file_id');\n\nconsole.log(response);\n\nconst content = await response.blob();\nconsole.log(content);", - }, - python: { - method: 'files.download', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.files.download(\n "file_id",\n)\nprint(response)\ncontent = response.read()\nprint(content)', - }, - go: { - method: 'client.Files.Download', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Files.Download(context.TODO(), "file_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/files/$FILE_ID/download \\\n -H "Authorization: Bearer $WRITER_API_KEY"', - }, - }, + "name": "download", + "endpoint": "/v1/files/{file_id}/download", + "httpMethod": "get", + "summary": "Download file", + "description": "Download the binary content of a file. The response will contain the file data in the appropriate MIME type.", + "stainlessPath": "(resource) files > (method) download", + "qualified": "client.files.download", + "params": [ + "file_id: string;" + ], + "response": "string", + "markdown": "## download\n\n`client.files.download(file_id: string): string`\n\n**get** `/v1/files/{file_id}/download`\n\nDownload the binary content of a file. The response will contain the file data in the appropriate MIME type.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.files.download('file_id');\n\nconsole.log(response);\n\nconst content = await response.blob()\nconsole.log(content)\n```", + "perLanguage": { + "typescript": { + "method": "client.files.download", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.files.download('file_id');\n\nconsole.log(response);\n\nconst content = await response.blob();\nconsole.log(content);" + }, + "python": { + "method": "files.download", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nresponse = client.files.download(\n \"file_id\",\n)\nprint(response)\ncontent = response.read()\nprint(content)" + }, + "go": { + "method": "client.Files.Download", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tresponse, err := client.Files.Download(context.TODO(), \"file_id\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", response)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/files/$FILE_ID/download \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" + } + } }, { - name: 'retry', - endpoint: '/v1/files/retry', - httpMethod: 'post', - summary: 'Retry failed files', - description: - 'Retry processing of files that previously failed to process. This will re-attempt the processing of the specified files.', - stainlessPath: '(resource) files > (method) retry', - qualified: 'client.files.retry', - params: ['file_ids: string[];'], - response: '{ success?: boolean; }', - markdown: - "## retry\n\n`client.files.retry(file_ids: string[]): { success?: boolean; }`\n\n**post** `/v1/files/retry`\n\nRetry processing of files that previously failed to process. This will re-attempt the processing of the specified files.\n\n### Parameters\n\n- `file_ids: string[]`\n The unique identifier of the files to retry.\n\n### Returns\n\n- `{ success?: boolean; }`\n\n - `success?: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.files.retry({ file_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(response);\n```", - perLanguage: { - typescript: { - method: 'client.files.retry', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.files.retry({ file_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(response.success);", - }, - python: { - method: 'files.retry', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.files.retry(\n file_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],\n)\nprint(response.success)', - }, - go: { - method: 'client.Files.Retry', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Files.Retry(context.TODO(), writersdk.FileRetryParams{\n\t\tFileIDs: writersdk.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Success)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/files/retry \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "file_ids": [\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"\n ]\n }\'', - }, - }, + "name": "retry", + "endpoint": "/v1/files/retry", + "httpMethod": "post", + "summary": "Retry failed files", + "description": "Retry processing of files that previously failed to process. This will re-attempt the processing of the specified files.", + "stainlessPath": "(resource) files > (method) retry", + "qualified": "client.files.retry", + "params": [ + "file_ids: string[];" + ], + "response": "{ success?: boolean; }", + "markdown": "## retry\n\n`client.files.retry(file_ids: string[]): { success?: boolean; }`\n\n**post** `/v1/files/retry`\n\nRetry processing of files that previously failed to process. This will re-attempt the processing of the specified files.\n\n### Parameters\n\n- `file_ids: string[]`\n The unique identifier of the files to retry.\n\n### Returns\n\n- `{ success?: boolean; }`\n\n - `success?: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.files.retry({ file_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(response);\n```", + "perLanguage": { + "typescript": { + "method": "client.files.retry", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.files.retry({ file_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(response.success);" + }, + "python": { + "method": "files.retry", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nresponse = client.files.retry(\n file_ids=[\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"],\n)\nprint(response.success)" + }, + "go": { + "method": "client.Files.Retry", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tresponse, err := client.Files.Retry(context.TODO(), writersdk.FileRetryParams{\n\t\tFileIDs: writersdk.F([]string{\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"}),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", response.Success)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/files/retry \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"file_ids\": [\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"\n ]\n }'" + } + } }, { - name: 'parse_pdf', - endpoint: '/v1/tools/pdf-parser/{file_id}', - httpMethod: 'post', - summary: 'Parse PDF', - description: 'Parse PDF to other formats.', - stainlessPath: '(resource) tools > (method) parse_pdf', - qualified: 'client.tools.parsePdf', - params: ['file_id: string;', "format: 'text' | 'markdown';"], - response: '{ content: string; }', - markdown: - "## parse_pdf\n\n`client.tools.parsePdf(file_id: string, format: 'text' | 'markdown'): { content: string; }`\n\n**post** `/v1/tools/pdf-parser/{file_id}`\n\nParse PDF to other formats.\n\n### Parameters\n\n- `file_id: string`\n\n- `format: 'text' | 'markdown'`\n The format into which the PDF content should be converted.\n\n### Returns\n\n- `{ content: string; }`\n\n - `content: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.tools.parsePdf('file_id', { format: 'text' });\n\nconsole.log(response);\n```", - perLanguage: { - typescript: { - method: 'client.tools.parsePdf', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.tools.parsePdf('file_id', { format: 'text' });\n\nconsole.log(response.content);", - }, - python: { - method: 'tools.parse_pdf', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.tools.parse_pdf(\n file_id="file_id",\n format="text",\n)\nprint(response.content)', - }, - go: { - method: 'client.Tools.ParsePdf', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Tools.ParsePdf(\n\t\tcontext.TODO(),\n\t\t"file_id",\n\t\twritersdk.ToolParsePdfParams{\n\t\t\tFormat: writersdk.F(writersdk.ToolParsePdfParamsFormatText),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Content)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/tools/pdf-parser/$FILE_ID \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "format": "text"\n }\'', - }, - }, + "name": "parse_pdf", + "endpoint": "/v1/tools/pdf-parser/{file_id}", + "httpMethod": "post", + "summary": "Parse PDF", + "description": "Parse PDF to other formats.", + "stainlessPath": "(resource) tools > (method) parse_pdf", + "qualified": "client.tools.parsePdf", + "params": [ + "file_id: string;", + "format: 'text' | 'markdown';" + ], + "response": "{ content: string; }", + "markdown": "## parse_pdf\n\n`client.tools.parsePdf(file_id: string, format: 'text' | 'markdown'): { content: string; }`\n\n**post** `/v1/tools/pdf-parser/{file_id}`\n\nParse PDF to other formats.\n\n### Parameters\n\n- `file_id: string`\n\n- `format: 'text' | 'markdown'`\n The format into which the PDF content should be converted.\n\n### Returns\n\n- `{ content: string; }`\n\n - `content: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.tools.parsePdf('file_id', { format: 'text' });\n\nconsole.log(response);\n```", + "perLanguage": { + "typescript": { + "method": "client.tools.parsePdf", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.tools.parsePdf('file_id', { format: 'text' });\n\nconsole.log(response.content);" + }, + "python": { + "method": "tools.parse_pdf", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nresponse = client.tools.parse_pdf(\n file_id=\"file_id\",\n format=\"text\",\n)\nprint(response.content)" + }, + "go": { + "method": "client.Tools.ParsePdf", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tresponse, err := client.Tools.ParsePdf(\n\t\tcontext.TODO(),\n\t\t\"file_id\",\n\t\twritersdk.ToolParsePdfParams{\n\t\t\tFormat: writersdk.F(writersdk.ToolParsePdfParamsFormatText),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", response.Content)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/tools/pdf-parser/$FILE_ID \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"format\": \"text\"\n }'" + } + } }, { - name: 'web_search', - endpoint: '/v1/tools/web-search', - httpMethod: 'post', - summary: 'Web search', - description: - 'Search the web for information about a given query and return relevant results with source URLs.', - stainlessPath: '(resource) tools > (method) web_search', - qualified: 'client.tools.webSearch', - params: [ - 'chunks_per_source?: number;', - 'country?: string;', - 'days?: number;', - 'exclude_domains?: string[];', - 'include_answer?: boolean;', - 'include_domains?: string[];', + "name": "web_search", + "endpoint": "/v1/tools/web-search", + "httpMethod": "post", + "summary": "Web search", + "description": "Search the web for information about a given query and return relevant results with source URLs.", + "stainlessPath": "(resource) tools > (method) web_search", + "qualified": "client.tools.webSearch", + "params": [ + "chunks_per_source?: number;", + "country?: string;", + "days?: number;", + "exclude_domains?: string[];", + "include_answer?: boolean;", + "include_domains?: string[];", "include_raw_content?: 'text' | 'markdown' | boolean;", - 'max_results?: number;', - 'query?: string;', + "max_results?: number;", + "query?: string;", "search_depth?: 'basic' | 'advanced';", - 'stream?: boolean;', + "stream?: boolean;", "time_range?: 'day' | 'week' | 'month' | 'year' | 'd' | 'w' | 'm' | 'y';", - "topic?: 'general' | 'news';", + "topic?: 'general' | 'news';" ], - response: '{ query: string; sources: { raw_content?: string; url?: string; }[]; answer?: string; }', - markdown: - "## web_search\n\n`client.tools.webSearch(chunks_per_source?: number, country?: string, days?: number, exclude_domains?: string[], include_answer?: boolean, include_domains?: string[], include_raw_content?: 'text' | 'markdown' | boolean, max_results?: number, query?: string, search_depth?: 'basic' | 'advanced', stream?: boolean, time_range?: 'day' | 'week' | 'month' | 'year' | 'd' | 'w' | 'm' | 'y', topic?: 'general' | 'news'): { query: string; sources: object[]; answer?: string; }`\n\n**post** `/v1/tools/web-search`\n\nSearch the web for information about a given query and return relevant results with source URLs.\n\n### Parameters\n\n- `chunks_per_source?: number`\n Only applies when `search_depth` is `advanced`. Specifies how many text segments to extract from each source. Limited to 3 chunks maximum.\n\n- `country?: string`\n Localizes search results to a specific country. Only applies to general topic searches.\n\n- `days?: number`\n For news topic searches, specifies how many days of news coverage to include.\n\n- `exclude_domains?: string[]`\n Domains to exclude from the search. If unset, the search includes all domains.\n\n- `include_answer?: boolean`\n Whether to include a generated answer to the query in the response. If `false`, only search results are returned.\n\n- `include_domains?: string[]`\n Domains to include in the search. If unset, the search includes all domains.\n\n- `include_raw_content?: 'text' | 'markdown' | boolean`\n Controls how raw content is included in search results:\n\n- `text`: Returns plain text without formatting markup\n- `markdown`: Returns structured content with markdown formatting (headers, links, bold text)\n- `true`: Same as `markdown`\n- `false`: Raw content is not included (default if unset)\n\n- `max_results?: number`\n Limits the number of search results returned. Cannot exceed 20 sources.\n\n- `query?: string`\n The search query.\n\n- `search_depth?: 'basic' | 'advanced'`\n Controls search comprehensiveness:\n\n- `basic`: Returns fewer but highly relevant results\n- `advanced`: Performs a deeper search with more results\n\n- `stream?: boolean`\n Enables streaming of search results as they become available.\n\n- `time_range?: 'day' | 'week' | 'month' | 'year' | 'd' | 'w' | 'm' | 'y'`\n Filters results to content published within the specified time range back from the current date. For example, `week` or `w` returns results from the past 7 days.\n\n- `topic?: 'general' | 'news'`\n The search topic category. Use `news` for current events and news articles, or `general` for broader web search.\n\n### Returns\n\n- `{ query: string; sources: { raw_content?: string; url?: string; }[]; answer?: string; }`\n\n - `query: string`\n - `sources: { raw_content?: string; url?: string; }[]`\n - `answer?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.tools.webSearch();\n\nconsole.log(response);\n```", - perLanguage: { - typescript: { - method: 'client.tools.webSearch', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.tools.webSearch({\n include_domains: ['dev.writer.com'],\n query: 'How do I get an API key for the Writer API?',\n});\n\nconsole.log(response.query);", - }, - python: { - method: 'tools.web_search', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.tools.web_search(\n include_domains=["dev.writer.com"],\n query="How do I get an API key for the Writer API?",\n)\nprint(response.query)', - }, - go: { - method: 'client.Tools.WebSearch', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Tools.WebSearch(context.TODO(), writersdk.ToolWebSearchParams{\n\t\tIncludeDomains: writersdk.F([]string{"dev.writer.com"}),\n\t\tQuery: writersdk.F("How do I get an API key for the Writer API?"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Query)\n}\n', - }, - http: { - example: - "curl https://api.writer.com/v1/tools/web-search \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'", - }, - }, + "response": "{ query: string; sources: { raw_content?: string; url?: string; }[]; answer?: string; }", + "markdown": "## web_search\n\n`client.tools.webSearch(chunks_per_source?: number, country?: string, days?: number, exclude_domains?: string[], include_answer?: boolean, include_domains?: string[], include_raw_content?: 'text' | 'markdown' | boolean, max_results?: number, query?: string, search_depth?: 'basic' | 'advanced', stream?: boolean, time_range?: 'day' | 'week' | 'month' | 'year' | 'd' | 'w' | 'm' | 'y', topic?: 'general' | 'news'): { query: string; sources: object[]; answer?: string; }`\n\n**post** `/v1/tools/web-search`\n\nSearch the web for information about a given query and return relevant results with source URLs.\n\n### Parameters\n\n- `chunks_per_source?: number`\n Only applies when `search_depth` is `advanced`. Specifies how many text segments to extract from each source. Limited to 3 chunks maximum.\n\n- `country?: string`\n Localizes search results to a specific country. Only applies to general topic searches.\n\n- `days?: number`\n For news topic searches, specifies how many days of news coverage to include.\n\n- `exclude_domains?: string[]`\n Domains to exclude from the search. If unset, the search includes all domains.\n\n- `include_answer?: boolean`\n Whether to include a generated answer to the query in the response. If `false`, only search results are returned.\n\n- `include_domains?: string[]`\n Domains to include in the search. If unset, the search includes all domains.\n\n- `include_raw_content?: 'text' | 'markdown' | boolean`\n Controls how raw content is included in search results:\n\n- `text`: Returns plain text without formatting markup\n- `markdown`: Returns structured content with markdown formatting (headers, links, bold text)\n- `true`: Same as `markdown`\n- `false`: Raw content is not included (default if unset)\n\n- `max_results?: number`\n Limits the number of search results returned. Cannot exceed 20 sources.\n\n- `query?: string`\n The search query.\n\n- `search_depth?: 'basic' | 'advanced'`\n Controls search comprehensiveness:\n\n- `basic`: Returns fewer but highly relevant results\n- `advanced`: Performs a deeper search with more results\n\n- `stream?: boolean`\n Enables streaming of search results as they become available.\n\n- `time_range?: 'day' | 'week' | 'month' | 'year' | 'd' | 'w' | 'm' | 'y'`\n Filters results to content published within the specified time range back from the current date. For example, `week` or `w` returns results from the past 7 days.\n\n- `topic?: 'general' | 'news'`\n The search topic category. Use `news` for current events and news articles, or `general` for broader web search.\n\n### Returns\n\n- `{ query: string; sources: { raw_content?: string; url?: string; }[]; answer?: string; }`\n\n - `query: string`\n - `sources: { raw_content?: string; url?: string; }[]`\n - `answer?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.tools.webSearch();\n\nconsole.log(response);\n```", + "perLanguage": { + "typescript": { + "method": "client.tools.webSearch", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.tools.webSearch({\n include_domains: ['dev.writer.com'],\n query: 'How do I get an API key for the Writer API?',\n});\n\nconsole.log(response.query);" + }, + "python": { + "method": "tools.web_search", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nresponse = client.tools.web_search(\n include_domains=[\"dev.writer.com\"],\n query=\"How do I get an API key for the Writer API?\",\n)\nprint(response.query)" + }, + "go": { + "method": "client.Tools.WebSearch", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tresponse, err := client.Tools.WebSearch(context.TODO(), writersdk.ToolWebSearchParams{\n\t\tIncludeDomains: writersdk.F([]string{\"dev.writer.com\"}),\n\t\tQuery: writersdk.F(\"How do I get an API key for the Writer API?\"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", response.Query)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/tools/web-search \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'" + } + } }, { - name: 'translate', - endpoint: '/v1/translation', - httpMethod: 'post', - summary: 'Translate text', - description: 'Translate text from one language to another.', - stainlessPath: '(resource) translation > (method) translate', - qualified: 'client.translation.translate', - params: [ - 'formality: boolean;', - 'length_control: boolean;', - 'mask_profanity: boolean;', + "name": "translate", + "endpoint": "/v1/translation", + "httpMethod": "post", + "summary": "Translate text", + "description": "Translate text from one language to another.", + "stainlessPath": "(resource) translation > (method) translate", + "qualified": "client.translation.translate", + "params": [ + "formality: boolean;", + "length_control: boolean;", + "mask_profanity: boolean;", "model: 'palmyra-translate';", - 'source_language_code: string;', - 'target_language_code: string;', - 'text: string;', + "source_language_code: string;", + "target_language_code: string;", + "text: string;" ], - response: '{ data: string; }', - markdown: - "## translate\n\n`client.translation.translate(formality: boolean, length_control: boolean, mask_profanity: boolean, model: 'palmyra-translate', source_language_code: string, target_language_code: string, text: string): { data: string; }`\n\n**post** `/v1/translation`\n\nTranslate text from one language to another.\n\n### Parameters\n\n- `formality: boolean`\n Whether to use formal or informal language in the translation. See the [list of languages that support formality](https://dev.writer.com/api-reference/translation-api/language-support#formality). If the language does not support formality, this parameter is ignored.\n\n- `length_control: boolean`\n Whether to control the length of the translated text. See the [list of languages that support length control](https://dev.writer.com/api-reference/translation-api/language-support#length-control). If the language does not support length control, this parameter is ignored.\n\n- `mask_profanity: boolean`\n Whether to mask profane words in the translated text. See the [list of languages that do not support profanity masking](https://dev.writer.com/api-reference/translation-api/language-support#profanity-masking). If the language does not support profanity masking, this parameter is ignored.\n\n- `model: 'palmyra-translate'`\n The model to use for translation.\n\n- `source_language_code: string`\n The [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) language code of the original text to translate. For example, `en` for English, `zh` for Chinese, `fr` for French, `es` for Spanish. If the language has a variant, the code appends the two-digit [ISO-3166 country code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes). For example, Mexican Spanish is `es-MX`. See the [list of supported languages and language codes](https://dev.writer.com/api-reference/translation-api/language-support).\n\n- `target_language_code: string`\n The [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) language code of the target language for the translation. For example, `en` for English, `zh` for Chinese, `fr` for French, `es` for Spanish. If the language has a variant, the code appends the two-digit [ISO-3166 country code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes). For example, Mexican Spanish is `es-MX`. See the [list of supported languages and language codes](https://dev.writer.com/api-reference/translation-api/language-support).\n\n- `text: string`\n The text to translate. Maximum of 100,000 words.\n\n### Returns\n\n- `{ data: string; }`\n\n - `data: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst translationResponse = await client.translation.translate({\n formality: true,\n length_control: true,\n mask_profanity: true,\n model: 'palmyra-translate',\n source_language_code: 'en',\n target_language_code: 'es',\n text: 'Hello, world!',\n});\n\nconsole.log(translationResponse);\n```", - perLanguage: { - typescript: { - method: 'client.translation.translate', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst translationResponse = await client.translation.translate({\n formality: true,\n length_control: true,\n mask_profanity: true,\n model: 'palmyra-translate',\n source_language_code: 'en',\n target_language_code: 'es',\n text: 'Hello, world!',\n});\n\nconsole.log(translationResponse.data);", - }, - python: { - method: 'translation.translate', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ntranslation_response = client.translation.translate(\n formality=True,\n length_control=True,\n mask_profanity=True,\n model="palmyra-translate",\n source_language_code="en",\n target_language_code="es",\n text="Hello, world!",\n)\nprint(translation_response.data)', - }, - go: { - method: 'client.Translation.Translate', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\ttranslationResponse, err := client.Translation.Translate(context.TODO(), writersdk.TranslationTranslateParams{\n\t\tTranslationRequest: writersdk.TranslationRequestParam{\n\t\t\tFormality: writersdk.F(true),\n\t\t\tLengthControl: writersdk.F(true),\n\t\t\tMaskProfanity: writersdk.F(true),\n\t\t\tModel: writersdk.F(writersdk.TranslationRequestModelPalmyraTranslate),\n\t\t\tSourceLanguageCode: writersdk.F("en"),\n\t\t\tTargetLanguageCode: writersdk.F("es"),\n\t\t\tText: writersdk.F("Hello, world!"),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", translationResponse.Data)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/translation \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "formality": true,\n "length_control": true,\n "mask_profanity": true,\n "model": "palmyra-translate",\n "source_language_code": "en",\n "target_language_code": "es",\n "text": "Hello, world!"\n }\'', - }, - }, + "response": "{ data: string; }", + "markdown": "## translate\n\n`client.translation.translate(formality: boolean, length_control: boolean, mask_profanity: boolean, model: 'palmyra-translate', source_language_code: string, target_language_code: string, text: string): { data: string; }`\n\n**post** `/v1/translation`\n\nTranslate text from one language to another.\n\n### Parameters\n\n- `formality: boolean`\n Whether to use formal or informal language in the translation. See the [list of languages that support formality](https://dev.writer.com/api-reference/translation-api/language-support#formality). If the language does not support formality, this parameter is ignored.\n\n- `length_control: boolean`\n Whether to control the length of the translated text. See the [list of languages that support length control](https://dev.writer.com/api-reference/translation-api/language-support#length-control). If the language does not support length control, this parameter is ignored.\n\n- `mask_profanity: boolean`\n Whether to mask profane words in the translated text. See the [list of languages that do not support profanity masking](https://dev.writer.com/api-reference/translation-api/language-support#profanity-masking). If the language does not support profanity masking, this parameter is ignored.\n\n- `model: 'palmyra-translate'`\n The model to use for translation.\n\n- `source_language_code: string`\n The [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) language code of the original text to translate. For example, `en` for English, `zh` for Chinese, `fr` for French, `es` for Spanish. If the language has a variant, the code appends the two-digit [ISO-3166 country code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes). For example, Mexican Spanish is `es-MX`. See the [list of supported languages and language codes](https://dev.writer.com/api-reference/translation-api/language-support).\n\n- `target_language_code: string`\n The [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) language code of the target language for the translation. For example, `en` for English, `zh` for Chinese, `fr` for French, `es` for Spanish. If the language has a variant, the code appends the two-digit [ISO-3166 country code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes). For example, Mexican Spanish is `es-MX`. See the [list of supported languages and language codes](https://dev.writer.com/api-reference/translation-api/language-support).\n\n- `text: string`\n The text to translate. Maximum of 100,000 words.\n\n### Returns\n\n- `{ data: string; }`\n\n - `data: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst translationResponse = await client.translation.translate({\n formality: true,\n length_control: true,\n mask_profanity: true,\n model: 'palmyra-translate',\n source_language_code: 'en',\n target_language_code: 'es',\n text: 'Hello, world!',\n});\n\nconsole.log(translationResponse);\n```", + "perLanguage": { + "typescript": { + "method": "client.translation.translate", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst translationResponse = await client.translation.translate({\n formality: true,\n length_control: true,\n mask_profanity: true,\n model: 'palmyra-translate',\n source_language_code: 'en',\n target_language_code: 'es',\n text: 'Hello, world!',\n});\n\nconsole.log(translationResponse.data);" + }, + "python": { + "method": "translation.translate", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\ntranslation_response = client.translation.translate(\n formality=True,\n length_control=True,\n mask_profanity=True,\n model=\"palmyra-translate\",\n source_language_code=\"en\",\n target_language_code=\"es\",\n text=\"Hello, world!\",\n)\nprint(translation_response.data)" + }, + "go": { + "method": "client.Translation.Translate", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\ttranslationResponse, err := client.Translation.Translate(context.TODO(), writersdk.TranslationTranslateParams{\n\t\tTranslationRequest: writersdk.TranslationRequestParam{\n\t\t\tFormality: writersdk.F(true),\n\t\t\tLengthControl: writersdk.F(true),\n\t\t\tMaskProfanity: writersdk.F(true),\n\t\t\tModel: writersdk.F(writersdk.TranslationRequestModelPalmyraTranslate),\n\t\t\tSourceLanguageCode: writersdk.F(\"en\"),\n\t\t\tTargetLanguageCode: writersdk.F(\"es\"),\n\t\t\tText: writersdk.F(\"Hello, world!\"),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", translationResponse.Data)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/translation \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"formality\": true,\n \"length_control\": true,\n \"mask_profanity\": true,\n \"model\": \"palmyra-translate\",\n \"source_language_code\": \"en\",\n \"target_language_code\": \"es\",\n \"text\": \"Hello, world!\"\n }'" + } + } }, { - name: 'analyze', - endpoint: '/v1/vision', - httpMethod: 'post', - summary: 'Analyze images', - description: - 'Submit images and documents with a prompt to generate an analysis. Supports JPG, PNG, PDF, and TXT files up to 7MB each.', - stainlessPath: '(resource) vision > (method) analyze', - qualified: 'client.vision.analyze', - params: [ + "name": "analyze", + "endpoint": "/v1/vision", + "httpMethod": "post", + "summary": "Analyze images", + "description": "Submit images and documents with a prompt to generate an analysis. Supports JPG, PNG, PDF, and TXT files up to 7MB each.", + "stainlessPath": "(resource) vision > (method) analyze", + "qualified": "client.vision.analyze", + "params": [ "model: 'palmyra-vision';", - 'prompt: string;', - 'variables: { file_id: string; name: string; }[];', + "prompt: string;", + "variables: { file_id: string; name: string; }[];" ], - response: '{ data: string; }', - markdown: - "## analyze\n\n`client.vision.analyze(model: 'palmyra-vision', prompt: string, variables: { file_id: string; name: string; }[]): { data: string; }`\n\n**post** `/v1/vision`\n\nSubmit images and documents with a prompt to generate an analysis. Supports JPG, PNG, PDF, and TXT files up to 7MB each.\n\n### Parameters\n\n- `model: 'palmyra-vision'`\n The model to use for image analysis.\n\n- `prompt: string`\n The prompt to use for the image analysis. The prompt must include the name of each image variable, surrounded by double curly braces (`{{}}`). For example, `Describe the difference between the image {{image_1}} and the image {{image_2}}`.\n\n- `variables: { file_id: string; name: string; }[]`\n\n### Returns\n\n- `{ data: string; }`\n\n - `data: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst visionResponse = await client.vision.analyze({\n model: 'palmyra-vision',\n prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.',\n variables: [{ file_id: 'f1234', name: 'image_1' }, { file_id: 'f9876', name: 'image_2' }],\n});\n\nconsole.log(visionResponse);\n```", - perLanguage: { - typescript: { - method: 'client.vision.analyze', - example: - "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst visionResponse = await client.vision.analyze({\n model: 'palmyra-vision',\n prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.',\n variables: [\n { name: 'image_1', file_id: 'f1234' },\n { name: 'image_2', file_id: 'f9876' },\n ],\n});\n\nconsole.log(visionResponse.data);", - }, - python: { - method: 'vision.analyze', - example: - 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nvision_response = client.vision.analyze(\n model="palmyra-vision",\n prompt="Describe the difference between the image {{image_1}} and the image {{image_2}}.",\n variables=[{\n "name": "image_1",\n "file_id": "f1234",\n }, {\n "name": "image_2",\n "file_id": "f9876",\n }],\n)\nprint(vision_response.data)', - }, - go: { - method: 'client.Vision.Analyze', - example: - 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tvisionResponse, err := client.Vision.Analyze(context.TODO(), writersdk.VisionAnalyzeParams{\n\t\tVisionRequest: writersdk.VisionRequestParam{\n\t\t\tModel: writersdk.F(writersdk.VisionRequestModelPalmyraVision),\n\t\t\tPrompt: writersdk.F("Describe the difference between the image {{image_1}} and the image {{image_2}}."),\n\t\t\tVariables: writersdk.F([]writersdk.VisionRequestVariableParam{{\n\t\t\t\tFileID: writersdk.F("f1234"),\n\t\t\t\tName: writersdk.F("image_1"),\n\t\t\t}, {\n\t\t\t\tFileID: writersdk.F("f9876"),\n\t\t\t\tName: writersdk.F("image_2"),\n\t\t\t}}),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", visionResponse.Data)\n}\n', - }, - http: { - example: - 'curl https://api.writer.com/v1/vision \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "model": "palmyra-vision",\n "prompt": "Describe the difference between the image {{image_1}} and the image {{image_2}}.",\n "variables": [\n {\n "file_id": "f1234",\n "name": "image_1"\n },\n {\n "file_id": "f9876",\n "name": "image_2"\n }\n ]\n }\'', - }, - }, - }, + "response": "{ data: string; }", + "markdown": "## analyze\n\n`client.vision.analyze(model: 'palmyra-vision', prompt: string, variables: { file_id: string; name: string; }[]): { data: string; }`\n\n**post** `/v1/vision`\n\nSubmit images and documents with a prompt to generate an analysis. Supports JPG, PNG, PDF, and TXT files up to 7MB each.\n\n### Parameters\n\n- `model: 'palmyra-vision'`\n The model to use for image analysis.\n\n- `prompt: string`\n The prompt to use for the image analysis. The prompt must include the name of each image variable, surrounded by double curly braces (`{{}}`). For example, `Describe the difference between the image {{image_1}} and the image {{image_2}}`.\n\n- `variables: { file_id: string; name: string; }[]`\n\n### Returns\n\n- `{ data: string; }`\n\n - `data: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst visionResponse = await client.vision.analyze({\n model: 'palmyra-vision',\n prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.',\n variables: [{ file_id: 'f1234', name: 'image_1' }, { file_id: 'f9876', name: 'image_2' }],\n});\n\nconsole.log(visionResponse);\n```", + "perLanguage": { + "typescript": { + "method": "client.vision.analyze", + "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst visionResponse = await client.vision.analyze({\n model: 'palmyra-vision',\n prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.',\n variables: [\n { name: 'image_1', file_id: 'f1234' },\n { name: 'image_2', file_id: 'f9876' },\n ],\n});\n\nconsole.log(visionResponse.data);" + }, + "python": { + "method": "vision.analyze", + "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nvision_response = client.vision.analyze(\n model=\"palmyra-vision\",\n prompt=\"Describe the difference between the image {{image_1}} and the image {{image_2}}.\",\n variables=[{\n \"name\": \"image_1\",\n \"file_id\": \"f1234\",\n }, {\n \"name\": \"image_2\",\n \"file_id\": \"f9876\",\n }],\n)\nprint(vision_response.data)" + }, + "go": { + "method": "client.Vision.Analyze", + "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tvisionResponse, err := client.Vision.Analyze(context.TODO(), writersdk.VisionAnalyzeParams{\n\t\tVisionRequest: writersdk.VisionRequestParam{\n\t\t\tModel: writersdk.F(writersdk.VisionRequestModelPalmyraVision),\n\t\t\tPrompt: writersdk.F(\"Describe the difference between the image {{image_1}} and the image {{image_2}}.\"),\n\t\t\tVariables: writersdk.F([]writersdk.VisionRequestVariableParam{{\n\t\t\t\tFileID: writersdk.F(\"f1234\"),\n\t\t\t\tName: writersdk.F(\"image_1\"),\n\t\t\t}, {\n\t\t\t\tFileID: writersdk.F(\"f9876\"),\n\t\t\t\tName: writersdk.F(\"image_2\"),\n\t\t\t}}),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", visionResponse.Data)\n}\n" + }, + "http": { + "example": "curl https://api.writer.com/v1/vision \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"model\": \"palmyra-vision\",\n \"prompt\": \"Describe the difference between the image {{image_1}} and the image {{image_2}}.\",\n \"variables\": [\n {\n \"file_id\": \"f1234\",\n \"name\": \"image_1\"\n },\n {\n \"file_id\": \"f9876\",\n \"name\": \"image_2\"\n }\n ]\n }'" + } + } + } ]; const EMBEDDED_READMES: { language: string; content: string }[] = [ { - language: 'go', - content: - '# Writer Go API Library\n\nGo Reference\n\nThe Writer Go library provides convenient access to the [Writer REST API](https://dev.writer.com/api-guides/introduction)\nfrom applications written in Go.\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n\n\n```go\nimport (\n\t"github.com/stainless-sdks/writer-go" // imported as SDK_PackageName\n)\n```\n\n\n\nOr to pin the version:\n\n\n\n```sh\ngo get -u \'github.com/stainless-sdks/writer-go@v0.0.1\'\n```\n\n\n\n## Requirements\n\nThis library requires Go 1.22+.\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```go\npackage main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n\t"github.com/stainless-sdks/writer-go/shared"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"), // defaults to os.LookupEnv("WRITER_API_KEY")\n\t)\n\tchatCompletion, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chatCompletion.ID)\n}\n\n```\n\n### Request fields\n\nAll request parameters are wrapped in a generic `Field` type,\nwhich we use to distinguish zero values from null or omitted fields.\n\nThis prevents accidentally sending a zero value if you forget a required parameter,\nand enables explicitly sending `null`, `false`, `\'\'`, or `0` on optional parameters.\nAny field not specified is not sent.\n\nTo construct fields with values, use the helpers `String()`, `Int()`, `Float()`, or most commonly, the generic `F[T]()`.\nTo send a null, use `Null[T]()`, and to send a nonconforming value, use `Raw[T](any)`. For example:\n\n```go\nparams := FooParams{\n\tName: SDK_PackageName.F("hello"),\n\n\t// Explicitly send `"description": null`\n\tDescription: SDK_PackageName.Null[string](),\n\n\tPoint: SDK_PackageName.F(SDK_PackageName.Point{\n\t\tX: SDK_PackageName.Int(0),\n\t\tY: SDK_PackageName.Int(1),\n\n\t\t// In cases where the API specifies a given type,\n\t\t// but you want to send something else, use `Raw`:\n\t\tZ: SDK_PackageName.Raw[int64](0.01), // sends a float\n\t}),\n}\n```\n\n### Response objects\n\nAll fields in response structs are value types (not pointers or wrappers).\n\nIf a given field is `null`, not present, or invalid, the corresponding field\nwill simply be its zero value.\n\nAll response structs also include a special `JSON` field, containing more detailed\ninformation about each property, which you can use like so:\n\n```go\nif res.Name == "" {\n\t// true if `"name"` is either not present or explicitly null\n\tres.JSON.Name.IsNull()\n\n\t// true if the `"name"` key was not present in the response JSON at all\n\tres.JSON.Name.IsMissing()\n\n\t// When the API returns data that cannot be coerced to the expected type:\n\tif res.JSON.Name.IsInvalid() {\n\t\traw := res.JSON.Name.Raw()\n\n\t\tlegacyName := struct{\n\t\t\tFirst string `json:"first"`\n\t\t\tLast string `json:"last"`\n\t\t}{}\n\t\tjson.Unmarshal([]byte(raw), &legacyName)\n\t\tname = legacyName.First + " " + legacyName.Last\n\t}\n}\n```\n\nThese `.JSON` structs also include an `Extras` map containing\nany properties in the json response that were not specified\nin the struct. This can be useful for API features not yet\npresent in the SDK.\n\n```go\nbody := res.JSON.ExtraFields["my_unexpected_field"].Raw()\n```\n\n### RequestOptions\n\nThis library uses the functional options pattern. Functions defined in the\n`SDK_PackageOptionName` package return a `RequestOption`, which is a closure that mutates a\n`RequestConfig`. These options can be supplied to the client or at individual\nrequests. For example:\n\n```go\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\t// Adds a header to every request made by the client\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "custom_header_info"),\n)\n\nclient.Chat.Chat(context.TODO(), ...,\n\t// Override the header\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "some_other_custom_header_info"),\n\t// Add an undocumented field to the request body, using sjson syntax\n\tSDK_PackageOptionName.WithJSONSet("some.json.path", map[string]string{"my": "object"}),\n)\n```\n\nSee the [full list of request options](https://pkg.go.dev/github.com/stainless-sdks/writer-go/SDK_PackageOptionName).\n\n### Pagination\n\nThis library provides some conveniences for working with paginated list endpoints.\n\nYou can use `.ListAutoPaging()` methods to iterate through items across all pages:\n\n```go\niter := client.Graphs.ListAutoPaging(context.TODO(), writersdk.GraphListParams{})\n// Automatically fetches more pages as needed.\nfor iter.Next() {\n\tgraph := iter.Current()\n\tfmt.Printf("%+v\\n", graph)\n}\nif err := iter.Err(); err != nil {\n\tpanic(err.Error())\n}\n```\n\nOr you can use simple `.List()` methods to fetch a single page and receive a standard response object\nwith additional helper methods like `.GetNextPage()`, e.g.:\n\n```go\npage, err := client.Graphs.List(context.TODO(), writersdk.GraphListParams{})\nfor page != nil {\n\tfor _, graph := range page.Data {\n\t\tfmt.Printf("%+v\\n", graph)\n\t}\n\tpage, err = page.GetNextPage()\n}\nif err != nil {\n\tpanic(err.Error())\n}\n```\n\n### Errors\n\nWhen the API returns a non-success status code, we return an error with type\n`*SDK_PackageName.Error`. This contains the `StatusCode`, `*http.Request`, and\n`*http.Response` values of the request, as well as the JSON of the error body\n(much like other response objects in the SDK).\n\nTo handle errors, we recommend that you use the `errors.As` pattern:\n\n```go\n_, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t}}),\n\tModel: writersdk.F("palmyra-x5"),\n})\nif err != nil {\n\tvar apierr *writersdk.Error\n\tif errors.As(err, &apierr) {\n\t\tprintln(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request\n\t\tprintln(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response\n\t}\n\tpanic(err.Error()) // GET "/v1/chat": 400 Bad Request { ... }\n}\n```\n\nWhen other errors occur, they are returned unwrapped; for example,\nif HTTP transport fails, you might receive `*url.Error` wrapping `*net.OpError`.\n\n### Timeouts\n\nRequests do not time out by default; use context to configure a timeout for a request lifecycle.\n\nNote that if a request is [retried](#retries), the context timeout does not start over.\nTo set a per-retry timeout, use `SDK_PackageOptionName.WithRequestTimeout()`.\n\n```go\n// This sets the timeout for the request, including all the retries.\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)\ndefer cancel()\nclient.Chat.Chat(\n\tctx,\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t},\n\t// This sets the per-retry timeout\n\toption.WithRequestTimeout(20*time.Second),\n)\n```\n\n### File uploads\n\nRequest parameters that correspond to file uploads in multipart requests are typed as\n`param.Field[io.Reader]`. The contents of the `io.Reader` will by default be sent as a multipart form\npart with the file name of "anonymous_file" and content-type of "application/octet-stream".\n\nThe file name and content-type can be customized by implementing `Name() string` or `ContentType()\nstring` on the run-time type of `io.Reader`. Note that `os.File` implements `Name() string`, so a\nfile returned by `os.Open` will be sent with the file name on disk.\n\nWe also provide a helper `SDK_PackageName.FileParam(reader io.Reader, filename string, contentType string)`\nwhich can be used to wrap any `io.Reader` with the appropriate file name and content type.\n\n\n\n### Retries\n\nCertain errors will be automatically retried 7 times by default, with a short exponential backoff.\nWe retry by default all connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit,\nand >=500 Internal errors.\n\nYou can use the `WithMaxRetries` option to configure or disable this:\n\n```go\n// Configure the default for all requests:\nclient := writersdk.NewClient(\n\toption.WithMaxRetries(0), // default is 2\n)\n\n// Override per-request:\nclient.Chat.Chat(\n\tcontext.TODO(),\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t},\n\toption.WithMaxRetries(5),\n)\n```\n\n\n### Accessing raw response data (e.g. response headers)\n\nYou can access the raw HTTP response data by using the `option.WithResponseInto()` request option. This is useful when\nyou need to examine response headers, status codes, or other details.\n\n```go\n// Create a variable to store the HTTP response\nvar response *http.Response\nchatCompletion, err := client.Chat.Chat(\n\tcontext.TODO(),\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t},\n\toption.WithResponseInto(&response),\n)\nif err != nil {\n\t// handle error\n}\nfmt.Printf("%+v\\n", chatCompletion)\n\nfmt.Printf("Status Code: %d\\n", response.StatusCode)\nfmt.Printf("Headers: %+#v\\n", response.Header)\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.Get`, `client.Post`, and other HTTP verbs.\n`RequestOptions` on the client, such as retries, will be respected when making these requests.\n\n```go\nvar (\n // params can be an io.Reader, a []byte, an encoding/json serializable object,\n // or a "…Params" struct defined in this library.\n params map[string]interface{}\n\n // result can be an []byte, *http.Response, a encoding/json deserializable object,\n // or a model defined in this library.\n result *http.Response\n)\nerr := client.Post(context.Background(), "/unspecified", params, &result)\nif err != nil {\n …\n}\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use either the `SDK_PackageOptionName.WithQuerySet()`\nor the `SDK_PackageOptionName.WithJSONSet()` methods.\n\n```go\nparams := FooNewParams{\n ID: SDK_PackageName.F("id_xxxx"),\n Data: SDK_PackageName.F(FooNewParamsData{\n FirstName: SDK_PackageName.F("John"),\n }),\n}\nclient.Foo.New(context.Background(), params, SDK_PackageOptionName.WithJSONSet("data.last_name", "Doe"))\n```\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may either access the raw JSON of the response as a string\nwith `result.JSON.RawJSON()`, or get the raw JSON of a particular field on the result with\n`result.JSON.Foo.Raw()`.\n\nAny fields that are not present on the response struct will be saved and can be accessed by `result.JSON.ExtraFields()` which returns the extra fields as a `map[string]Field`.\n\n### Middleware\n\nWe provide `SDK_PackageOptionName.WithMiddleware` which applies the given\nmiddleware to requests.\n\n```go\nfunc Logger(req *http.Request, next SDK_PackageOptionName.MiddlewareNext) (res *http.Response, err error) {\n\t// Before the request\n\tstart := time.Now()\n\tLogReq(req)\n\n\t// Forward the request to the next handler\n\tres, err = next(req)\n\n\t// Handle stuff after the request\n\tend := time.Now()\n\tLogRes(res, err, start - end)\n\n return res, err\n}\n\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\tSDK_PackageOptionName.WithMiddleware(Logger),\n)\n```\n\nWhen multiple middlewares are provided as variadic arguments, the middlewares\nare applied left to right. If `SDK_PackageOptionName.WithMiddleware` is given\nmultiple times, for example first in the client then the method, the\nmiddleware in the client will run first and the middleware given in the method\nwill run next.\n\nYou may also replace the default `http.Client` with\n`SDK_PackageOptionName.WithHTTPClient(client)`. Only one http client is\naccepted (this overwrites any previous client) and receives requests after any\nmiddleware has been applied.\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/writer-go/issues) with questions, bugs, or suggestions.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n', + "language": "go", + "content": "# Writer Go API Library\n\n\"Go\n\nThe Writer Go library provides convenient access to the [Writer REST API](https://dev.writer.com/api-guides/introduction)\nfrom applications written in Go.\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n\n\n```go\nimport (\n\t\"github.com/stainless-sdks/writer-go\" // imported as SDK_PackageName\n)\n```\n\n\n\nOr to pin the version:\n\n\n\n```sh\ngo get -u 'github.com/stainless-sdks/writer-go@v0.0.1'\n```\n\n\n\n## Requirements\n\nThis library requires Go 1.22+.\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n\t\"github.com/stainless-sdks/writer-go/shared\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"), // defaults to os.LookupEnv(\"WRITER_API_KEY\")\n\t)\n\tchatCompletion, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString(\"Write a haiku about programming\")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F(\"palmyra-x5\"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", chatCompletion.ID)\n}\n\n```\n\n### Request fields\n\nAll request parameters are wrapped in a generic `Field` type,\nwhich we use to distinguish zero values from null or omitted fields.\n\nThis prevents accidentally sending a zero value if you forget a required parameter,\nand enables explicitly sending `null`, `false`, `''`, or `0` on optional parameters.\nAny field not specified is not sent.\n\nTo construct fields with values, use the helpers `String()`, `Int()`, `Float()`, or most commonly, the generic `F[T]()`.\nTo send a null, use `Null[T]()`, and to send a nonconforming value, use `Raw[T](any)`. For example:\n\n```go\nparams := FooParams{\n\tName: SDK_PackageName.F(\"hello\"),\n\n\t// Explicitly send `\"description\": null`\n\tDescription: SDK_PackageName.Null[string](),\n\n\tPoint: SDK_PackageName.F(SDK_PackageName.Point{\n\t\tX: SDK_PackageName.Int(0),\n\t\tY: SDK_PackageName.Int(1),\n\n\t\t// In cases where the API specifies a given type,\n\t\t// but you want to send something else, use `Raw`:\n\t\tZ: SDK_PackageName.Raw[int64](0.01), // sends a float\n\t}),\n}\n```\n\n### Response objects\n\nAll fields in response structs are value types (not pointers or wrappers).\n\nIf a given field is `null`, not present, or invalid, the corresponding field\nwill simply be its zero value.\n\nAll response structs also include a special `JSON` field, containing more detailed\ninformation about each property, which you can use like so:\n\n```go\nif res.Name == \"\" {\n\t// true if `\"name\"` is either not present or explicitly null\n\tres.JSON.Name.IsNull()\n\n\t// true if the `\"name\"` key was not present in the response JSON at all\n\tres.JSON.Name.IsMissing()\n\n\t// When the API returns data that cannot be coerced to the expected type:\n\tif res.JSON.Name.IsInvalid() {\n\t\traw := res.JSON.Name.Raw()\n\n\t\tlegacyName := struct{\n\t\t\tFirst string `json:\"first\"`\n\t\t\tLast string `json:\"last\"`\n\t\t}{}\n\t\tjson.Unmarshal([]byte(raw), &legacyName)\n\t\tname = legacyName.First + \" \" + legacyName.Last\n\t}\n}\n```\n\nThese `.JSON` structs also include an `Extras` map containing\nany properties in the json response that were not specified\nin the struct. This can be useful for API features not yet\npresent in the SDK.\n\n```go\nbody := res.JSON.ExtraFields[\"my_unexpected_field\"].Raw()\n```\n\n### RequestOptions\n\nThis library uses the functional options pattern. Functions defined in the\n`SDK_PackageOptionName` package return a `RequestOption`, which is a closure that mutates a\n`RequestConfig`. These options can be supplied to the client or at individual\nrequests. For example:\n\n```go\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\t// Adds a header to every request made by the client\n\tSDK_PackageOptionName.WithHeader(\"X-Some-Header\", \"custom_header_info\"),\n)\n\nclient.Chat.Chat(context.TODO(), ...,\n\t// Override the header\n\tSDK_PackageOptionName.WithHeader(\"X-Some-Header\", \"some_other_custom_header_info\"),\n\t// Add an undocumented field to the request body, using sjson syntax\n\tSDK_PackageOptionName.WithJSONSet(\"some.json.path\", map[string]string{\"my\": \"object\"}),\n)\n```\n\nSee the [full list of request options](https://pkg.go.dev/github.com/stainless-sdks/writer-go/SDK_PackageOptionName).\n\n### Pagination\n\nThis library provides some conveniences for working with paginated list endpoints.\n\nYou can use `.ListAutoPaging()` methods to iterate through items across all pages:\n\n```go\niter := client.Graphs.ListAutoPaging(context.TODO(), writersdk.GraphListParams{})\n// Automatically fetches more pages as needed.\nfor iter.Next() {\n\tgraph := iter.Current()\n\tfmt.Printf(\"%+v\\n\", graph)\n}\nif err := iter.Err(); err != nil {\n\tpanic(err.Error())\n}\n```\n\nOr you can use simple `.List()` methods to fetch a single page and receive a standard response object\nwith additional helper methods like `.GetNextPage()`, e.g.:\n\n```go\npage, err := client.Graphs.List(context.TODO(), writersdk.GraphListParams{})\nfor page != nil {\n\tfor _, graph := range page.Data {\n\t\tfmt.Printf(\"%+v\\n\", graph)\n\t}\n\tpage, err = page.GetNextPage()\n}\nif err != nil {\n\tpanic(err.Error())\n}\n```\n\n### Errors\n\nWhen the API returns a non-success status code, we return an error with type\n`*SDK_PackageName.Error`. This contains the `StatusCode`, `*http.Request`, and\n`*http.Response` values of the request, as well as the JSON of the error body\n(much like other response objects in the SDK).\n\nTo handle errors, we recommend that you use the `errors.As` pattern:\n\n```go\n_, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString(\"Write a haiku about programming\")),\n\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t}}),\n\tModel: writersdk.F(\"palmyra-x5\"),\n})\nif err != nil {\n\tvar apierr *writersdk.Error\n\tif errors.As(err, &apierr) {\n\t\tprintln(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request\n\t\tprintln(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response\n\t}\n\tpanic(err.Error()) // GET \"/v1/chat\": 400 Bad Request { ... }\n}\n```\n\nWhen other errors occur, they are returned unwrapped; for example,\nif HTTP transport fails, you might receive `*url.Error` wrapping `*net.OpError`.\n\n### Timeouts\n\nRequests do not time out by default; use context to configure a timeout for a request lifecycle.\n\nNote that if a request is [retried](#retries), the context timeout does not start over.\nTo set a per-retry timeout, use `SDK_PackageOptionName.WithRequestTimeout()`.\n\n```go\n// This sets the timeout for the request, including all the retries.\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)\ndefer cancel()\nclient.Chat.Chat(\n\tctx,\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString(\"Write a haiku about programming\")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F(\"palmyra-x5\"),\n\t},\n\t// This sets the per-retry timeout\n\toption.WithRequestTimeout(20*time.Second),\n)\n```\n\n### File uploads\n\nRequest parameters that correspond to file uploads in multipart requests are typed as\n`param.Field[io.Reader]`. The contents of the `io.Reader` will by default be sent as a multipart form\npart with the file name of \"anonymous_file\" and content-type of \"application/octet-stream\".\n\nThe file name and content-type can be customized by implementing `Name() string` or `ContentType()\nstring` on the run-time type of `io.Reader`. Note that `os.File` implements `Name() string`, so a\nfile returned by `os.Open` will be sent with the file name on disk.\n\nWe also provide a helper `SDK_PackageName.FileParam(reader io.Reader, filename string, contentType string)`\nwhich can be used to wrap any `io.Reader` with the appropriate file name and content type.\n\n\n\n### Retries\n\nCertain errors will be automatically retried 7 times by default, with a short exponential backoff.\nWe retry by default all connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit,\nand >=500 Internal errors.\n\nYou can use the `WithMaxRetries` option to configure or disable this:\n\n```go\n// Configure the default for all requests:\nclient := writersdk.NewClient(\n\toption.WithMaxRetries(0), // default is 2\n)\n\n// Override per-request:\nclient.Chat.Chat(\n\tcontext.TODO(),\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString(\"Write a haiku about programming\")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F(\"palmyra-x5\"),\n\t},\n\toption.WithMaxRetries(5),\n)\n```\n\n\n### Accessing raw response data (e.g. response headers)\n\nYou can access the raw HTTP response data by using the `option.WithResponseInto()` request option. This is useful when\nyou need to examine response headers, status codes, or other details.\n\n```go\n// Create a variable to store the HTTP response\nvar response *http.Response\nchatCompletion, err := client.Chat.Chat(\n\tcontext.TODO(),\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString(\"Write a haiku about programming\")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F(\"palmyra-x5\"),\n\t},\n\toption.WithResponseInto(&response),\n)\nif err != nil {\n\t// handle error\n}\nfmt.Printf(\"%+v\\n\", chatCompletion)\n\nfmt.Printf(\"Status Code: %d\\n\", response.StatusCode)\nfmt.Printf(\"Headers: %+#v\\n\", response.Header)\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.Get`, `client.Post`, and other HTTP verbs.\n`RequestOptions` on the client, such as retries, will be respected when making these requests.\n\n```go\nvar (\n // params can be an io.Reader, a []byte, an encoding/json serializable object,\n // or a \"…Params\" struct defined in this library.\n params map[string]interface{}\n\n // result can be an []byte, *http.Response, a encoding/json deserializable object,\n // or a model defined in this library.\n result *http.Response\n)\nerr := client.Post(context.Background(), \"/unspecified\", params, &result)\nif err != nil {\n …\n}\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use either the `SDK_PackageOptionName.WithQuerySet()`\nor the `SDK_PackageOptionName.WithJSONSet()` methods.\n\n```go\nparams := FooNewParams{\n ID: SDK_PackageName.F(\"id_xxxx\"),\n Data: SDK_PackageName.F(FooNewParamsData{\n FirstName: SDK_PackageName.F(\"John\"),\n }),\n}\nclient.Foo.New(context.Background(), params, SDK_PackageOptionName.WithJSONSet(\"data.last_name\", \"Doe\"))\n```\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may either access the raw JSON of the response as a string\nwith `result.JSON.RawJSON()`, or get the raw JSON of a particular field on the result with\n`result.JSON.Foo.Raw()`.\n\nAny fields that are not present on the response struct will be saved and can be accessed by `result.JSON.ExtraFields()` which returns the extra fields as a `map[string]Field`.\n\n### Middleware\n\nWe provide `SDK_PackageOptionName.WithMiddleware` which applies the given\nmiddleware to requests.\n\n```go\nfunc Logger(req *http.Request, next SDK_PackageOptionName.MiddlewareNext) (res *http.Response, err error) {\n\t// Before the request\n\tstart := time.Now()\n\tLogReq(req)\n\n\t// Forward the request to the next handler\n\tres, err = next(req)\n\n\t// Handle stuff after the request\n\tend := time.Now()\n\tLogRes(res, err, start - end)\n\n return res, err\n}\n\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\tSDK_PackageOptionName.WithMiddleware(Logger),\n)\n```\n\nWhen multiple middlewares are provided as variadic arguments, the middlewares\nare applied left to right. If `SDK_PackageOptionName.WithMiddleware` is given\nmultiple times, for example first in the client then the method, the\nmiddleware in the client will run first and the middleware given in the method\nwill run next.\n\nYou may also replace the default `http.Client` with\n`SDK_PackageOptionName.WithHTTPClient(client)`. Only one http client is\naccepted (this overwrites any previous client) and receives requests after any\nmiddleware has been applied.\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/writer-go/issues) with questions, bugs, or suggestions.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n" }, { - language: 'python', - content: - '# Writer Python API library\n\n\n[![PyPI version](https://img.shields.io/pypi/v/writer-sdk.svg?label=pypi%20(stable))](https://pypi.org/project/writer-sdk/)\n\nThe Writer Python library provides convenient access to the Writer REST API from any Python 3.9+\napplication. The library includes type definitions for all request params and response fields,\nand offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nThe REST API documentation can be found on [dev.writer.com](https://dev.writer.com/api-guides/introduction). The full API of this library can be found in [api.md](api.md).\n\n## Installation\n\n```sh\n# install from PyPI\npip install writer-sdk\n```\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```python\nimport os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\n\nchat_completion = client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\nprint(chat_completion.id)\n```\n\nWhile you can provide an `api_key` keyword argument,\nwe recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)\nto add `WRITER_API_KEY="My API Key"` to your `.env` file\nso that your API Key is not stored in source control.\n\n## Async usage\n\nSimply import `AsyncWriter` instead of `Writer` and use `await` with each API call:\n\n```python\nimport os\nimport asyncio\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\n\nasync def main() -> None:\n chat_completion = await client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n )\n print(chat_completion.id)\n\nasyncio.run(main())\n```\n\nFunctionality between the synchronous and asynchronous clients is otherwise identical.\n\n### With aiohttp\n\nBy default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.\n\nYou can enable this by installing `aiohttp`:\n\n```sh\n# install from PyPI\npip install writer-sdk[aiohttp]\n```\n\nThen you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:\n\n```python\nimport os\nimport asyncio\nfrom writerai import DefaultAioHttpClient\nfrom writerai import AsyncWriter\n\nasync def main() -> None:\n async with AsyncWriter(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n http_client=DefaultAioHttpClient(),\n) as client:\n chat_completion = await client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n )\n print(chat_completion.id)\n\nasyncio.run(main())\n```\n\n## Streaming responses\n\nWe provide support for streaming responses using Server Side Events (SSE).\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nstream = client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n stream=True,\n)\nfor chat_completion in stream:\n print(chat_completion.id)\n```\n\nThe async client uses the exact same interface.\n\n```python\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter()\n\nstream = await client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n stream=True,\n)\nasync for chat_completion in stream:\n print(chat_completion.id)\n```\n\n## Using types\n\nNested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:\n\n- Serializing back into JSON, `model.to_json()`\n- Converting to a dictionary, `model.to_dict()`\n\nTyped requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.\n\n## Pagination\n\nList methods in the Writer API are paginated.\n\nThis library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nall_graphs = []\n# Automatically fetches more pages as needed.\nfor graph in client.graphs.list():\n # Do something with graph here\n all_graphs.append(graph)\nprint(all_graphs)\n```\n\nOr, asynchronously:\n\n```python\nimport asyncio\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter()\n\nasync def main() -> None:\n all_graphs = []\n # Iterate through items across all pages, issuing requests as needed.\n async for graph in client.graphs.list():\n all_graphs.append(graph)\n print(all_graphs)\n\nasyncio.run(main())\n```\n\nAlternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:\n\n```python\nfirst_page = await client.graphs.list()\nif first_page.has_next_page():\n print(f"will fetch next page using these details: {first_page.next_page_info()}")\n next_page = await first_page.get_next_page()\n print(f"number of items we just fetched: {len(next_page.data)}")\n\n# Remove `await` for non-async usage.\n```\n\nOr just work directly with the returned data:\n\n```python\nfirst_page = await client.graphs.list()\n\nprint(f"next page cursor: {first_page.after}") # => "next page cursor: ..."\nfor graph in first_page.data:\n print(graph.id)\n\n# Remove `await` for non-async usage.\n```\n\n## Nested params\n\nNested parameters are dictionaries, typed using `TypedDict`, for example:\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nchat_completion = client.chat.chat(\n messages=[{\n "role": "user"\n }],\n model="model",\n response_format={\n "type": "text"\n },\n)\nprint(chat_completion.response_format)\n```\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `writerai.APIConnectionError` is raised.\n\nWhen the API returns a non-success status code (that is, 4xx or 5xx\nresponse), a subclass of `writerai.APIStatusError` is raised, containing `status_code` and `response` properties.\n\nAll errors inherit from `writerai.APIError`.\n\n```python\nimport writerai\nfrom writerai import Writer\n\nclient = Writer()\n\ntry:\n client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n )\nexcept writerai.APIConnectionError as e:\n print("The server could not be reached")\n print(e.__cause__) # an underlying Exception, likely raised within httpx.\nexcept writerai.RateLimitError as e:\n print("A 429 status code was received; we should back off a bit.")\nexcept writerai.APIStatusError as e:\n print("Another non-200-range status code was received")\n print(e.status_code)\n print(e.response)\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors are automatically retried 7 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors are all retried by default.\n\nYou can use the `max_retries` option to configure or disable retry settings:\n\n```python\nfrom writerai import Writer\n\n# Configure the default for all requests:\nclient = Writer(\n # default is 2\n max_retries=0,\n)\n\n# Or, configure per-request:\nclient.with_options(max_retries = 5).chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\n```\n\n### Timeouts\n\nBy default requests time out after 3 minutes. You can configure this with a `timeout` option,\nwhich accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:\n\n```python\nfrom writerai import Writer\n\n# Configure the default for all requests:\nclient = Writer(\n # 20 seconds (default is 3 minutes)\n timeout=20.0,\n)\n\n# More granular control:\nclient = Writer(\n timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),\n)\n\n# Override per-request:\nclient.with_options(timeout = 5.0).chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\n```\n\nOn timeout, an `APITimeoutError` is thrown.\n\nNote that requests that time out are [retried twice by default](#retries).\n\n\n\n## Advanced\n\n### Logging\n\nWe use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.\n\nYou can enable logging by setting the environment variable `WRITER_LOG` to `info`.\n\n```shell\n$ export WRITER_LOG=info\n```\n\nOr to `debug` for more verbose logging.\n\n### How to tell whether `None` means `null` or missing\n\nIn an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:\n\n```py\nif response.my_field is None:\n if \'my_field\' not in response.model_fields_set:\n print(\'Got json like {}, without a "my_field" key present at all.\')\n else:\n print(\'Got json like {"my_field": null}.\')\n```\n\n### Accessing raw response data (e.g. headers)\n\nThe "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,\n\n```py\nfrom writerai import Writer\n\nclient = Writer()\nresponse = client.chat.with_raw_response.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\nprint(response.headers.get(\'X-My-Header\'))\n\nchat = response.parse() # get the object that `chat.chat()` would have returned\nprint(chat.id)\n```\n\nThese methods return an [`APIResponse`](https://github.com/writer/writer-python/tree/main/src/writerai/_response.py) object.\n\nThe async client returns an [`AsyncAPIResponse`](https://github.com/writer/writer-python/tree/main/src/writerai/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.\n\n#### `.with_streaming_response`\n\nThe above interface eagerly reads the full response body when you make the request, which may not always be what you want.\n\nTo stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.\n\n```python\nwith client.chat.with_streaming_response.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n) as response :\n print(response.headers.get(\'X-My-Header\'))\n\n for line in response.iter_lines():\n print(line)\n```\n\nThe context manager is required so that the response will reliably be closed.\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API.\n\nIf you need to access undocumented endpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other\nhttp verbs. Options on the client will be respected (such as retries) when making this request.\n\n```py\nimport httpx\n\nresponse = client.post(\n "/foo",\n cast_to=httpx.Response,\n body={"my_param": True},\n)\n\nprint(response.headers.get("x-foo"))\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You\ncan also get all the extra fields on the Pydantic model as a dict with\n[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).\n\n### Configuring the HTTP client\n\nYou can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:\n\n- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)\n- Custom [transports](https://www.python-httpx.org/advanced/transports/)\n- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality\n\n```python\nimport httpx\nfrom writerai import Writer, DefaultHttpxClient\n\nclient = Writer(\n # Or use the `WRITER_BASE_URL` env var\n base_url="http://my.test.server.example.com:8083",\n http_client=DefaultHttpxClient(proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0")),\n)\n```\n\nYou can also customize the client on a per-request basis by using `with_options()`:\n\n```python\nclient.with_options(http_client=DefaultHttpxClient(...))\n```\n\n### Managing HTTP resources\n\nBy default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.\n\n```py\nfrom writerai import Writer\n\nwith Writer() as client:\n # make requests here\n ...\n\n# HTTP client is now closed\n```\n\n## Versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/writer/writer-python/issues) with questions, bugs, or suggestions.\n\n### Determining the installed version\n\nIf you\'ve upgraded to the latest version but aren\'t seeing any new features you were expecting then your python environment is likely still using an older version.\n\nYou can determine the version that is being used at runtime with:\n\n```py\nimport writerai\nprint(writerai.__version__)\n```\n\n## Requirements\n\nPython 3.9 or higher.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n', + "language": "python", + "content": "# Writer Python API library\n\n\n[![PyPI version](https://img.shields.io/pypi/v/writer-sdk.svg?label=pypi%20(stable))](https://pypi.org/project/writer-sdk/)\n\nThe Writer Python library provides convenient access to the Writer REST API from any Python 3.9+\napplication. The library includes type definitions for all request params and response fields,\nand offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nThe REST API documentation can be found on [dev.writer.com](https://dev.writer.com/api-guides/introduction). The full API of this library can be found in [api.md](api.md).\n\n## Installation\n\n```sh\n# install from PyPI\npip install writer-sdk\n```\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```python\nimport os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\n\nchat_completion = client.chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n)\nprint(chat_completion.id)\n```\n\nWhile you can provide an `api_key` keyword argument,\nwe recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)\nto add `WRITER_API_KEY=\"My API Key\"` to your `.env` file\nso that your API Key is not stored in source control.\n\n## Async usage\n\nSimply import `AsyncWriter` instead of `Writer` and use `await` with each API call:\n\n```python\nimport os\nimport asyncio\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\n\nasync def main() -> None:\n chat_completion = await client.chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n )\n print(chat_completion.id)\n\nasyncio.run(main())\n```\n\nFunctionality between the synchronous and asynchronous clients is otherwise identical.\n\n### With aiohttp\n\nBy default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.\n\nYou can enable this by installing `aiohttp`:\n\n```sh\n# install from PyPI\npip install writer-sdk[aiohttp]\n```\n\nThen you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:\n\n```python\nimport os\nimport asyncio\nfrom writerai import DefaultAioHttpClient\nfrom writerai import AsyncWriter\n\nasync def main() -> None:\n async with AsyncWriter(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n http_client=DefaultAioHttpClient(),\n) as client:\n chat_completion = await client.chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n )\n print(chat_completion.id)\n\nasyncio.run(main())\n```\n\n## Streaming responses\n\nWe provide support for streaming responses using Server Side Events (SSE).\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nstream = client.chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n stream=True,\n)\nfor chat_completion in stream:\n print(chat_completion.id)\n```\n\nThe async client uses the exact same interface.\n\n```python\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter()\n\nstream = await client.chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n stream=True,\n)\nasync for chat_completion in stream:\n print(chat_completion.id)\n```\n\n## Using types\n\nNested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:\n\n- Serializing back into JSON, `model.to_json()`\n- Converting to a dictionary, `model.to_dict()`\n\nTyped requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.\n\n## Pagination\n\nList methods in the Writer API are paginated.\n\nThis library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nall_graphs = []\n# Automatically fetches more pages as needed.\nfor graph in client.graphs.list():\n # Do something with graph here\n all_graphs.append(graph)\nprint(all_graphs)\n```\n\nOr, asynchronously:\n\n```python\nimport asyncio\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter()\n\nasync def main() -> None:\n all_graphs = []\n # Iterate through items across all pages, issuing requests as needed.\n async for graph in client.graphs.list():\n all_graphs.append(graph)\n print(all_graphs)\n\nasyncio.run(main())\n```\n\nAlternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:\n\n```python\nfirst_page = await client.graphs.list()\nif first_page.has_next_page():\n print(f\"will fetch next page using these details: {first_page.next_page_info()}\")\n next_page = await first_page.get_next_page()\n print(f\"number of items we just fetched: {len(next_page.data)}\")\n\n# Remove `await` for non-async usage.\n```\n\nOr just work directly with the returned data:\n\n```python\nfirst_page = await client.graphs.list()\n\nprint(f\"next page cursor: {first_page.after}\") # => \"next page cursor: ...\"\nfor graph in first_page.data:\n print(graph.id)\n\n# Remove `await` for non-async usage.\n```\n\n## Nested params\n\nNested parameters are dictionaries, typed using `TypedDict`, for example:\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nchat_completion = client.chat.chat(\n messages=[{\n \"role\": \"user\"\n }],\n model=\"model\",\n response_format={\n \"type\": \"text\"\n },\n)\nprint(chat_completion.response_format)\n```\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `writerai.APIConnectionError` is raised.\n\nWhen the API returns a non-success status code (that is, 4xx or 5xx\nresponse), a subclass of `writerai.APIStatusError` is raised, containing `status_code` and `response` properties.\n\nAll errors inherit from `writerai.APIError`.\n\n```python\nimport writerai\nfrom writerai import Writer\n\nclient = Writer()\n\ntry:\n client.chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n )\nexcept writerai.APIConnectionError as e:\n print(\"The server could not be reached\")\n print(e.__cause__) # an underlying Exception, likely raised within httpx.\nexcept writerai.RateLimitError as e:\n print(\"A 429 status code was received; we should back off a bit.\")\nexcept writerai.APIStatusError as e:\n print(\"Another non-200-range status code was received\")\n print(e.status_code)\n print(e.response)\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors are automatically retried 7 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors are all retried by default.\n\nYou can use the `max_retries` option to configure or disable retry settings:\n\n```python\nfrom writerai import Writer\n\n# Configure the default for all requests:\nclient = Writer(\n # default is 2\n max_retries=0,\n)\n\n# Or, configure per-request:\nclient.with_options(max_retries = 5).chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n)\n```\n\n### Timeouts\n\nBy default requests time out after 3 minutes. You can configure this with a `timeout` option,\nwhich accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:\n\n```python\nfrom writerai import Writer\n\n# Configure the default for all requests:\nclient = Writer(\n # 20 seconds (default is 3 minutes)\n timeout=20.0,\n)\n\n# More granular control:\nclient = Writer(\n timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),\n)\n\n# Override per-request:\nclient.with_options(timeout = 5.0).chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n)\n```\n\nOn timeout, an `APITimeoutError` is thrown.\n\nNote that requests that time out are [retried twice by default](#retries).\n\n\n\n## Advanced\n\n### Logging\n\nWe use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.\n\nYou can enable logging by setting the environment variable `WRITER_LOG` to `info`.\n\n```shell\n$ export WRITER_LOG=info\n```\n\nOr to `debug` for more verbose logging.\n\n### How to tell whether `None` means `null` or missing\n\nIn an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:\n\n```py\nif response.my_field is None:\n if 'my_field' not in response.model_fields_set:\n print('Got json like {}, without a \"my_field\" key present at all.')\n else:\n print('Got json like {\"my_field\": null}.')\n```\n\n### Accessing raw response data (e.g. headers)\n\nThe \"raw\" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,\n\n```py\nfrom writerai import Writer\n\nclient = Writer()\nresponse = client.chat.with_raw_response.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n)\nprint(response.headers.get('X-My-Header'))\n\nchat = response.parse() # get the object that `chat.chat()` would have returned\nprint(chat.id)\n```\n\nThese methods return an [`APIResponse`](https://github.com/writer/writer-python/tree/main/src/writerai/_response.py) object.\n\nThe async client returns an [`AsyncAPIResponse`](https://github.com/writer/writer-python/tree/main/src/writerai/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.\n\n#### `.with_streaming_response`\n\nThe above interface eagerly reads the full response body when you make the request, which may not always be what you want.\n\nTo stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.\n\n```python\nwith client.chat.with_streaming_response.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n) as response :\n print(response.headers.get('X-My-Header'))\n\n for line in response.iter_lines():\n print(line)\n```\n\nThe context manager is required so that the response will reliably be closed.\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API.\n\nIf you need to access undocumented endpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other\nhttp verbs. Options on the client will be respected (such as retries) when making this request.\n\n```py\nimport httpx\n\nresponse = client.post(\n \"/foo\",\n cast_to=httpx.Response,\n body={\"my_param\": True},\n)\n\nprint(response.headers.get(\"x-foo\"))\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You\ncan also get all the extra fields on the Pydantic model as a dict with\n[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).\n\n### Configuring the HTTP client\n\nYou can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:\n\n- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)\n- Custom [transports](https://www.python-httpx.org/advanced/transports/)\n- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality\n\n```python\nimport httpx\nfrom writerai import Writer, DefaultHttpxClient\n\nclient = Writer(\n # Or use the `WRITER_BASE_URL` env var\n base_url=\"http://my.test.server.example.com:8083\",\n http_client=DefaultHttpxClient(proxy=\"http://my.test.proxy.example.com\", transport=httpx.HTTPTransport(local_address=\"0.0.0.0\")),\n)\n```\n\nYou can also customize the client on a per-request basis by using `with_options()`:\n\n```python\nclient.with_options(http_client=DefaultHttpxClient(...))\n```\n\n### Managing HTTP resources\n\nBy default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.\n\n```py\nfrom writerai import Writer\n\nwith Writer() as client:\n # make requests here\n ...\n\n# HTTP client is now closed\n```\n\n## Versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/writer/writer-python/issues) with questions, bugs, or suggestions.\n\n### Determining the installed version\n\nIf you've upgraded to the latest version but aren't seeing any new features you were expecting then your python environment is likely still using an older version.\n\nYou can determine the version that is being used at runtime with:\n\n```py\nimport writerai\nprint(writerai.__version__)\n```\n\n## Requirements\n\nPython 3.9 or higher.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n" }, { - language: 'typescript', - content: - "# Writer TypeScript API Library\n\n[![NPM version](https://img.shields.io/npm/v/writer-sdk.svg?label=npm%20(stable))](https://npmjs.org/package/writer-sdk) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/writer-sdk)\n\nThis library provides convenient access to the Writer REST API from server-side TypeScript or JavaScript.\n\n\n\nThe REST API documentation can be found on [dev.writer.com](https://dev.writer.com/api-guides/introduction). The full API of this library can be found in [api.md](api.md).\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n```sh\nnpm install writer-sdk\n```\n\n\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n\n```js\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst chatCompletion = await client.chat.chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n});\n\nconsole.log(chatCompletion.id);\n```\n\n## Streaming responses\n\nWe provide support for streaming responses using Server Sent Events (SSE).\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.chat.chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n stream: true,\n});\nfor await (const chatCompletionChunk of stream) {\n console.log(chatCompletionChunk.id);\n}\n```\n\nIf you need to cancel a stream, you can `break` from the loop\nor call `stream.controller.abort()`.\n\n### Request & Response types\n\nThis library includes TypeScript definitions for all request params and response fields. You may import and use them like so:\n\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst params: Writer.ChatChatParams = {\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n};\nconst chatCompletion: Writer.ChatCompletion = await client.chat.chat(params);\n```\n\nDocumentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.\n\n\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API,\nor if the API returns a non-success status code (i.e., 4xx or 5xx response),\na subclass of `APIError` will be thrown:\n\n\n```ts\nconst chatCompletion = await client.chat\n .chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n })\n .catch(async (err) => {\n if (err instanceof Writer.APIError) {\n console.log(err.status); // 400\n console.log(err.name); // BadRequestError\n console.log(err.headers); // {server: 'nginx', ...}\n } else {\n throw err;\n }\n });\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors will be automatically retried 7 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors will all be retried by default.\n\nYou can use the `maxRetries` option to configure or disable this:\n\n\n```js\n// Configure the default for all requests:\nconst client = new Writer({\n maxRetries: 0, // default is 2\n});\n\n// Or, configure per-request:\nawait client.chat.chat({ messages: [{ content: 'Write a haiku about programming', role: 'user' }], model: 'palmyra-x5' }, {\n maxRetries: 5,\n});\n```\n\n### Timeouts\n\nRequests time out after 3 minutes by default. You can configure this with a `timeout` option:\n\n\n```ts\n// Configure the default for all requests:\nconst client = new Writer({\n timeout: 20 * 1000, // 20 seconds (default is 3 minutes)\n});\n\n// Override per-request:\nawait client.chat.chat({ messages: [{ content: 'Write a haiku about programming', role: 'user' }], model: 'palmyra-x5' }, {\n timeout: 5 * 1000,\n});\n```\n\nOn timeout, an `APIConnectionTimeoutError` is thrown.\n\nNote that requests which time out will be [retried twice by default](#retries).\n\n## Auto-pagination\n\nList methods in the Writer API are paginated.\nYou can use the `for await … of` syntax to iterate through items across all pages:\n\n```ts\nasync function fetchAllGraphs(params) {\n const allGraphs = [];\n // Automatically fetches more pages as needed.\n for await (const graph of client.graphs.list()) {\n allGraphs.push(graph);\n }\n return allGraphs;\n}\n```\n\nAlternatively, you can request a single page at a time:\n\n```ts\nlet page = await client.graphs.list();\nfor (const graph of page.data) {\n console.log(graph);\n}\n\n// Convenience methods are provided for manually paginating:\nwhile (page.hasNextPage()) {\n page = await page.getNextPage();\n // ...\n}\n```\n\n\n\n## Advanced Usage\n\n### Accessing raw Response data (e.g., headers)\n\nThe \"raw\" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return.\nThis method returns as soon as the headers for a successful response are received and does not consume the response body, so you are free to write custom parsing or streaming logic.\n\nYou can also use the `.withResponse()` method to get the raw `Response` along with the parsed data.\nUnlike `.asResponse()` this method consumes the body, returning once it is parsed.\n\n\n```ts\nconst client = new Writer();\n\nconst response = await client.chat\n .chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n })\n .asResponse();\nconsole.log(response.headers.get('X-My-Header'));\nconsole.log(response.statusText); // access the underlying Response object\n\nconst { data: chatCompletion, response: raw } = await client.chat\n .chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n })\n .withResponse();\nconsole.log(raw.headers.get('X-My-Header'));\nconsole.log(chatCompletion.id);\n```\n\n### Logging\n\n> [!IMPORTANT]\n> All log messages are intended for debugging only. The format and content of log messages\n> may change between releases.\n\n#### Log levels\n\nThe log level can be configured in two ways:\n\n1. Via the `WRITER_LOG` environment variable\n2. Using the `logLevel` client option (overrides the environment variable if set)\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n logLevel: 'debug', // Show all log messages\n});\n```\n\nAvailable log levels, from most to least verbose:\n\n- `'debug'` - Show debug messages, info, warnings, and errors\n- `'info'` - Show info messages, warnings, and errors\n- `'warn'` - Show warnings and errors (default)\n- `'error'` - Show only errors\n- `'off'` - Disable all logging\n\nAt the `'debug'` level, all HTTP requests and responses are logged, including headers and bodies.\nSome authentication-related headers are redacted, but sensitive data in request and response bodies\nmay still be visible.\n\n#### Custom logger\n\nBy default, this library logs to `globalThis.console`. You can also provide a custom logger.\nMost logging libraries are supported, including [pino](https://www.npmjs.com/package/pino), [winston](https://www.npmjs.com/package/winston), [bunyan](https://www.npmjs.com/package/bunyan), [consola](https://www.npmjs.com/package/consola), [signale](https://www.npmjs.com/package/signale), and [@std/log](https://jsr.io/@std/log). If your logger doesn't work, please open an issue.\n\nWhen providing a custom logger, the `logLevel` option still controls which messages are emitted, messages\nbelow the configured level will not be sent to your logger.\n\n```ts\nimport Writer from 'writer-sdk';\nimport pino from 'pino';\n\nconst logger = pino();\n\nconst client = new Writer({\n logger: logger.child({ name: 'Writer' }),\n logLevel: 'debug', // Send all messages to pino, allowing it to filter\n});\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs.\nOptions on the client, such as retries, will be respected when making these requests.\n\n```ts\nawait client.post('/some/path', {\n body: { some_prop: 'foo' },\n query: { some_query_arg: 'bar' },\n});\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented\nparameter. This library doesn't validate at runtime that the request matches the type, so any extra values you\nsend will be sent as-is.\n\n```ts\nclient.chat.chat({\n // ...\n // @ts-expect-error baz is not yet public\n baz: 'undocumented option',\n});\n```\n\nFor requests with the `GET` verb, any extra params will be in the query, all other requests will send the\nextra param in the body.\n\nIf you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may access the response object with `// @ts-expect-error` on\nthe response object, or cast the response object to the requisite type. Like the request params, we do not\nvalidate or strip extra properties from the response from the API.\n\n### Customizing the fetch client\n\nBy default, this library expects a global `fetch` function is defined.\n\nIf you want to use a different `fetch` function, you can either polyfill the global:\n\n```ts\nimport fetch from 'my-fetch';\n\nglobalThis.fetch = fetch;\n```\n\nOr pass it to the client:\n\n```ts\nimport Writer from 'writer-sdk';\nimport fetch from 'my-fetch';\n\nconst client = new Writer({ fetch });\n```\n\n### Fetch options\n\nIf you want to set custom `fetch` options without overriding the `fetch` function, you can provide a `fetchOptions` object when instantiating the client or making a request. (Request-specific options override client options.)\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n fetchOptions: {\n // `RequestInit` options\n },\n});\n```\n\n#### Configuring proxies\n\nTo modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy\noptions to requests:\n\n **Node** [[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)]\n\n```ts\nimport Writer from 'writer-sdk';\nimport * as undici from 'undici';\n\nconst proxyAgent = new undici.ProxyAgent('http://localhost:8888');\nconst client = new Writer({\n fetchOptions: {\n dispatcher: proxyAgent,\n },\n});\n```\n\n **Bun** [[docs](https://bun.sh/guides/http/proxy)]\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n fetchOptions: {\n proxy: 'http://localhost:8888',\n },\n});\n```\n\n **Deno** [[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)]\n\n```ts\nimport Writer from 'npm:writer-sdk';\n\nconst httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });\nconst client = new Writer({\n fetchOptions: {\n client: httpClient,\n },\n});\n```\n\n## Frequently Asked Questions\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/writer/writer-node/issues) with questions, bugs, or suggestions.\n\n## Requirements\n\nTypeScript >= 4.9 is supported.\n\nThe following runtimes are supported:\n\n- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more)\n- Node.js 20 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions.\n- Deno v1.28.0 or higher.\n- Bun 1.0 or later.\n- Cloudflare Workers.\n- Vercel Edge Runtime.\n- Jest 28 or greater with the `\"node\"` environment (`\"jsdom\"` is not supported at this time).\n- Nitro v2.6 or greater.\n\nNote that React Native is not supported at this time.\n\nIf you are interested in other runtime environments, please open or upvote an issue on GitHub.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n", - }, + "language": "typescript", + "content": "# Writer TypeScript API Library\n\n[![NPM version](https://img.shields.io/npm/v/writer-sdk.svg?label=npm%20(stable))](https://npmjs.org/package/writer-sdk) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/writer-sdk)\n\nThis library provides convenient access to the Writer REST API from server-side TypeScript or JavaScript.\n\n\n\nThe REST API documentation can be found on [dev.writer.com](https://dev.writer.com/api-guides/introduction). The full API of this library can be found in [api.md](api.md).\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n```sh\nnpm install writer-sdk\n```\n\n\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n\n```js\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst chatCompletion = await client.chat.chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n});\n\nconsole.log(chatCompletion.id);\n```\n\n## Streaming responses\n\nWe provide support for streaming responses using Server Sent Events (SSE).\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.chat.chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n stream: true,\n});\nfor await (const chatCompletionChunk of stream) {\n console.log(chatCompletionChunk.id);\n}\n```\n\nIf you need to cancel a stream, you can `break` from the loop\nor call `stream.controller.abort()`.\n\n### Request & Response types\n\nThis library includes TypeScript definitions for all request params and response fields. You may import and use them like so:\n\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst params: Writer.ChatChatParams = {\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n};\nconst chatCompletion: Writer.ChatCompletion = await client.chat.chat(params);\n```\n\nDocumentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.\n\n\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API,\nor if the API returns a non-success status code (i.e., 4xx or 5xx response),\na subclass of `APIError` will be thrown:\n\n\n```ts\nconst chatCompletion = await client.chat\n .chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n })\n .catch(async (err) => {\n if (err instanceof Writer.APIError) {\n console.log(err.status); // 400\n console.log(err.name); // BadRequestError\n console.log(err.headers); // {server: 'nginx', ...}\n } else {\n throw err;\n }\n });\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors will be automatically retried 7 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors will all be retried by default.\n\nYou can use the `maxRetries` option to configure or disable this:\n\n\n```js\n// Configure the default for all requests:\nconst client = new Writer({\n maxRetries: 0, // default is 2\n});\n\n// Or, configure per-request:\nawait client.chat.chat({ messages: [{ content: 'Write a haiku about programming', role: 'user' }], model: 'palmyra-x5' }, {\n maxRetries: 5,\n});\n```\n\n### Timeouts\n\nRequests time out after 3 minutes by default. You can configure this with a `timeout` option:\n\n\n```ts\n// Configure the default for all requests:\nconst client = new Writer({\n timeout: 20 * 1000, // 20 seconds (default is 3 minutes)\n});\n\n// Override per-request:\nawait client.chat.chat({ messages: [{ content: 'Write a haiku about programming', role: 'user' }], model: 'palmyra-x5' }, {\n timeout: 5 * 1000,\n});\n```\n\nOn timeout, an `APIConnectionTimeoutError` is thrown.\n\nNote that requests which time out will be [retried twice by default](#retries).\n\n## Auto-pagination\n\nList methods in the Writer API are paginated.\nYou can use the `for await … of` syntax to iterate through items across all pages:\n\n```ts\nasync function fetchAllGraphs(params) {\n const allGraphs = [];\n // Automatically fetches more pages as needed.\n for await (const graph of client.graphs.list()) {\n allGraphs.push(graph);\n }\n return allGraphs;\n}\n```\n\nAlternatively, you can request a single page at a time:\n\n```ts\nlet page = await client.graphs.list();\nfor (const graph of page.data) {\n console.log(graph);\n}\n\n// Convenience methods are provided for manually paginating:\nwhile (page.hasNextPage()) {\n page = await page.getNextPage();\n // ...\n}\n```\n\n\n\n## Advanced Usage\n\n### Accessing raw Response data (e.g., headers)\n\nThe \"raw\" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return.\nThis method returns as soon as the headers for a successful response are received and does not consume the response body, so you are free to write custom parsing or streaming logic.\n\nYou can also use the `.withResponse()` method to get the raw `Response` along with the parsed data.\nUnlike `.asResponse()` this method consumes the body, returning once it is parsed.\n\n\n```ts\nconst client = new Writer();\n\nconst response = await client.chat\n .chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n })\n .asResponse();\nconsole.log(response.headers.get('X-My-Header'));\nconsole.log(response.statusText); // access the underlying Response object\n\nconst { data: chatCompletion, response: raw } = await client.chat\n .chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n })\n .withResponse();\nconsole.log(raw.headers.get('X-My-Header'));\nconsole.log(chatCompletion.id);\n```\n\n### Logging\n\n> [!IMPORTANT]\n> All log messages are intended for debugging only. The format and content of log messages\n> may change between releases.\n\n#### Log levels\n\nThe log level can be configured in two ways:\n\n1. Via the `WRITER_LOG` environment variable\n2. Using the `logLevel` client option (overrides the environment variable if set)\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n logLevel: 'debug', // Show all log messages\n});\n```\n\nAvailable log levels, from most to least verbose:\n\n- `'debug'` - Show debug messages, info, warnings, and errors\n- `'info'` - Show info messages, warnings, and errors\n- `'warn'` - Show warnings and errors (default)\n- `'error'` - Show only errors\n- `'off'` - Disable all logging\n\nAt the `'debug'` level, all HTTP requests and responses are logged, including headers and bodies.\nSome authentication-related headers are redacted, but sensitive data in request and response bodies\nmay still be visible.\n\n#### Custom logger\n\nBy default, this library logs to `globalThis.console`. You can also provide a custom logger.\nMost logging libraries are supported, including [pino](https://www.npmjs.com/package/pino), [winston](https://www.npmjs.com/package/winston), [bunyan](https://www.npmjs.com/package/bunyan), [consola](https://www.npmjs.com/package/consola), [signale](https://www.npmjs.com/package/signale), and [@std/log](https://jsr.io/@std/log). If your logger doesn't work, please open an issue.\n\nWhen providing a custom logger, the `logLevel` option still controls which messages are emitted, messages\nbelow the configured level will not be sent to your logger.\n\n```ts\nimport Writer from 'writer-sdk';\nimport pino from 'pino';\n\nconst logger = pino();\n\nconst client = new Writer({\n logger: logger.child({ name: 'Writer' }),\n logLevel: 'debug', // Send all messages to pino, allowing it to filter\n});\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs.\nOptions on the client, such as retries, will be respected when making these requests.\n\n```ts\nawait client.post('/some/path', {\n body: { some_prop: 'foo' },\n query: { some_query_arg: 'bar' },\n});\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented\nparameter. This library doesn't validate at runtime that the request matches the type, so any extra values you\nsend will be sent as-is.\n\n```ts\nclient.chat.chat({\n // ...\n // @ts-expect-error baz is not yet public\n baz: 'undocumented option',\n});\n```\n\nFor requests with the `GET` verb, any extra params will be in the query, all other requests will send the\nextra param in the body.\n\nIf you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may access the response object with `// @ts-expect-error` on\nthe response object, or cast the response object to the requisite type. Like the request params, we do not\nvalidate or strip extra properties from the response from the API.\n\n### Customizing the fetch client\n\nBy default, this library expects a global `fetch` function is defined.\n\nIf you want to use a different `fetch` function, you can either polyfill the global:\n\n```ts\nimport fetch from 'my-fetch';\n\nglobalThis.fetch = fetch;\n```\n\nOr pass it to the client:\n\n```ts\nimport Writer from 'writer-sdk';\nimport fetch from 'my-fetch';\n\nconst client = new Writer({ fetch });\n```\n\n### Fetch options\n\nIf you want to set custom `fetch` options without overriding the `fetch` function, you can provide a `fetchOptions` object when instantiating the client or making a request. (Request-specific options override client options.)\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n fetchOptions: {\n // `RequestInit` options\n },\n});\n```\n\n#### Configuring proxies\n\nTo modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy\noptions to requests:\n\n **Node** [[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)]\n\n```ts\nimport Writer from 'writer-sdk';\nimport * as undici from 'undici';\n\nconst proxyAgent = new undici.ProxyAgent('http://localhost:8888');\nconst client = new Writer({\n fetchOptions: {\n dispatcher: proxyAgent,\n },\n});\n```\n\n **Bun** [[docs](https://bun.sh/guides/http/proxy)]\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n fetchOptions: {\n proxy: 'http://localhost:8888',\n },\n});\n```\n\n **Deno** [[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)]\n\n```ts\nimport Writer from 'npm:writer-sdk';\n\nconst httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });\nconst client = new Writer({\n fetchOptions: {\n client: httpClient,\n },\n});\n```\n\n## Frequently Asked Questions\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/writer/writer-node/issues) with questions, bugs, or suggestions.\n\n## Requirements\n\nTypeScript >= 4.9 is supported.\n\nThe following runtimes are supported:\n\n- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more)\n- Node.js 20 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions.\n- Deno v1.28.0 or higher.\n- Bun 1.0 or later.\n- Cloudflare Workers.\n- Vercel Edge Runtime.\n- Jest 28 or greater with the `\"node\"` environment (`\"jsdom\"` is not supported at this time).\n- Nitro v2.6 or greater.\n\nNote that React Native is not supported at this time.\n\nIf you are interested in other runtime environments, please open or upvote an issue on GitHub.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n" + } ]; const INDEX_OPTIONS = { @@ -1252,18 +1127,21 @@ export class LocalDocsSearch { maxResults?: number; maxLength?: number; }): SearchResult { - const { query, language = 'typescript', detail = 'default', maxResults = 5, maxLength = 100_000 } = props; + const { + query, + language = 'typescript', + detail = 'default', + maxResults = 5, + maxLength = 100_000, + } = props; const useMarkdown = detail === 'verbose' || detail === 'high'; // Search both indices and merge results by score. // Filter prose hits so language-tagged content (READMEs and docs with // frontmatter) only matches the requested language. - const methodHits = this.methodIndex - .search(query) - .map((hit) => ({ ...hit, _kind: 'http_method' as const })); - const proseHits = this.proseIndex - .search(query) + const methodHits = this.methodIndex.search(query).map((hit) => ({ ...hit, _kind: 'http_method' as const })); + const proseHits = this.proseIndex.search(query) .filter((hit) => { const source = ((hit as Record)['_original'] as ProseChunk | undefined)?.source; if (!source) return true; diff --git a/packages/mcp-server/src/methods.ts b/packages/mcp-server/src/methods.ts index c20ca99b..9cb7f919 100644 --- a/packages/mcp-server/src/methods.ts +++ b/packages/mcp-server/src/methods.ts @@ -7,190 +7,159 @@ export type SdkMethod = { fullyQualifiedName: string; httpMethod?: 'get' | 'post' | 'put' | 'patch' | 'delete' | 'query'; httpPath?: string; -}; +} -export const sdkMethods: SdkMethod[] = [ - { - clientCallName: 'client.applications.retrieve', - fullyQualifiedName: 'applications.retrieve', - httpMethod: 'get', - httpPath: '/v1/applications/{application_id}', - }, - { - clientCallName: 'client.applications.list', - fullyQualifiedName: 'applications.list', - httpMethod: 'get', - httpPath: '/v1/applications', - }, - { - clientCallName: 'client.applications.generateContent', - fullyQualifiedName: 'applications.generateContent', - httpMethod: 'post', - httpPath: '/v1/applications/{application_id}', - }, - { - clientCallName: 'client.applications.jobs.create', - fullyQualifiedName: 'applications.jobs.create', - httpMethod: 'post', - httpPath: '/v1/applications/{application_id}/jobs', - }, - { - clientCallName: 'client.applications.jobs.retrieve', - fullyQualifiedName: 'applications.jobs.retrieve', - httpMethod: 'get', - httpPath: '/v1/applications/jobs/{job_id}', - }, - { - clientCallName: 'client.applications.jobs.list', - fullyQualifiedName: 'applications.jobs.list', - httpMethod: 'get', - httpPath: '/v1/applications/{application_id}/jobs', - }, - { - clientCallName: 'client.applications.jobs.retry', - fullyQualifiedName: 'applications.jobs.retry', - httpMethod: 'post', - httpPath: '/v1/applications/jobs/{job_id}/retry', - }, - { - clientCallName: 'client.applications.graphs.update', - fullyQualifiedName: 'applications.graphs.update', - httpMethod: 'put', - httpPath: '/v1/applications/{application_id}/graphs', - }, - { - clientCallName: 'client.applications.graphs.list', - fullyQualifiedName: 'applications.graphs.list', - httpMethod: 'get', - httpPath: '/v1/applications/{application_id}/graphs', - }, - { - clientCallName: 'client.chat.chat', - fullyQualifiedName: 'chat.chat', - httpMethod: 'post', - httpPath: '/v1/chat', - }, - { - clientCallName: 'client.completions.create', - fullyQualifiedName: 'completions.create', - httpMethod: 'post', - httpPath: '/v1/completions', - }, - { - clientCallName: 'client.models.list', - fullyQualifiedName: 'models.list', - httpMethod: 'get', - httpPath: '/v1/models', - }, - { - clientCallName: 'client.graphs.create', - fullyQualifiedName: 'graphs.create', - httpMethod: 'post', - httpPath: '/v1/graphs', - }, - { - clientCallName: 'client.graphs.retrieve', - fullyQualifiedName: 'graphs.retrieve', - httpMethod: 'get', - httpPath: '/v1/graphs/{graph_id}', - }, - { - clientCallName: 'client.graphs.update', - fullyQualifiedName: 'graphs.update', - httpMethod: 'put', - httpPath: '/v1/graphs/{graph_id}', - }, - { - clientCallName: 'client.graphs.list', - fullyQualifiedName: 'graphs.list', - httpMethod: 'get', - httpPath: '/v1/graphs', - }, - { - clientCallName: 'client.graphs.delete', - fullyQualifiedName: 'graphs.delete', - httpMethod: 'delete', - httpPath: '/v1/graphs/{graph_id}', - }, - { - clientCallName: 'client.graphs.addFileToGraph', - fullyQualifiedName: 'graphs.addFileToGraph', - httpMethod: 'post', - httpPath: '/v1/graphs/{graph_id}/file', - }, - { - clientCallName: 'client.graphs.question', - fullyQualifiedName: 'graphs.question', - httpMethod: 'post', - httpPath: '/v1/graphs/question', - }, - { - clientCallName: 'client.graphs.removeFileFromGraph', - fullyQualifiedName: 'graphs.removeFileFromGraph', - httpMethod: 'delete', - httpPath: '/v1/graphs/{graph_id}/file/{file_id}', - }, - { - clientCallName: 'client.files.retrieve', - fullyQualifiedName: 'files.retrieve', - httpMethod: 'get', - httpPath: '/v1/files/{file_id}', - }, - { - clientCallName: 'client.files.list', - fullyQualifiedName: 'files.list', - httpMethod: 'get', - httpPath: '/v1/files', - }, - { - clientCallName: 'client.files.delete', - fullyQualifiedName: 'files.delete', - httpMethod: 'delete', - httpPath: '/v1/files/{file_id}', - }, - { - clientCallName: 'client.files.download', - fullyQualifiedName: 'files.download', - httpMethod: 'get', - httpPath: '/v1/files/{file_id}/download', - }, - { - clientCallName: 'client.files.retry', - fullyQualifiedName: 'files.retry', - httpMethod: 'post', - httpPath: '/v1/files/retry', - }, - { - clientCallName: 'client.files.upload', - fullyQualifiedName: 'files.upload', - httpMethod: 'post', - httpPath: '/v1/files', - }, - { - clientCallName: 'client.tools.parsePdf', - fullyQualifiedName: 'tools.parsePdf', - httpMethod: 'post', - httpPath: '/v1/tools/pdf-parser/{file_id}', - }, - { - clientCallName: 'client.tools.webSearch', - fullyQualifiedName: 'tools.webSearch', - httpMethod: 'post', - httpPath: '/v1/tools/web-search', - }, - { - clientCallName: 'client.translation.translate', - fullyQualifiedName: 'translation.translate', - httpMethod: 'post', - httpPath: '/v1/translation', - }, - { - clientCallName: 'client.vision.analyze', - fullyQualifiedName: 'vision.analyze', - httpMethod: 'post', - httpPath: '/v1/vision', - }, -]; +export const sdkMethods: SdkMethod[] = [{ + clientCallName: 'client.applications.retrieve', + fullyQualifiedName: 'applications.retrieve', + httpMethod: 'get', + httpPath: '/v1/applications/{application_id}', +},{ + clientCallName: 'client.applications.list', + fullyQualifiedName: 'applications.list', + httpMethod: 'get', + httpPath: '/v1/applications', +},{ + clientCallName: 'client.applications.generateContent', + fullyQualifiedName: 'applications.generateContent', + httpMethod: 'post', + httpPath: '/v1/applications/{application_id}', +},{ + clientCallName: 'client.applications.jobs.create', + fullyQualifiedName: 'applications.jobs.create', + httpMethod: 'post', + httpPath: '/v1/applications/{application_id}/jobs', +},{ + clientCallName: 'client.applications.jobs.retrieve', + fullyQualifiedName: 'applications.jobs.retrieve', + httpMethod: 'get', + httpPath: '/v1/applications/jobs/{job_id}', +},{ + clientCallName: 'client.applications.jobs.list', + fullyQualifiedName: 'applications.jobs.list', + httpMethod: 'get', + httpPath: '/v1/applications/{application_id}/jobs', +},{ + clientCallName: 'client.applications.jobs.retry', + fullyQualifiedName: 'applications.jobs.retry', + httpMethod: 'post', + httpPath: '/v1/applications/jobs/{job_id}/retry', +},{ + clientCallName: 'client.applications.graphs.update', + fullyQualifiedName: 'applications.graphs.update', + httpMethod: 'put', + httpPath: '/v1/applications/{application_id}/graphs', +},{ + clientCallName: 'client.applications.graphs.list', + fullyQualifiedName: 'applications.graphs.list', + httpMethod: 'get', + httpPath: '/v1/applications/{application_id}/graphs', +},{ + clientCallName: 'client.chat.chat', + fullyQualifiedName: 'chat.chat', + httpMethod: 'post', + httpPath: '/v1/chat', +},{ + clientCallName: 'client.completions.create', + fullyQualifiedName: 'completions.create', + httpMethod: 'post', + httpPath: '/v1/completions', +},{ + clientCallName: 'client.models.list', + fullyQualifiedName: 'models.list', + httpMethod: 'get', + httpPath: '/v1/models', +},{ + clientCallName: 'client.graphs.create', + fullyQualifiedName: 'graphs.create', + httpMethod: 'post', + httpPath: '/v1/graphs', +},{ + clientCallName: 'client.graphs.retrieve', + fullyQualifiedName: 'graphs.retrieve', + httpMethod: 'get', + httpPath: '/v1/graphs/{graph_id}', +},{ + clientCallName: 'client.graphs.update', + fullyQualifiedName: 'graphs.update', + httpMethod: 'put', + httpPath: '/v1/graphs/{graph_id}', +},{ + clientCallName: 'client.graphs.list', + fullyQualifiedName: 'graphs.list', + httpMethod: 'get', + httpPath: '/v1/graphs', +},{ + clientCallName: 'client.graphs.delete', + fullyQualifiedName: 'graphs.delete', + httpMethod: 'delete', + httpPath: '/v1/graphs/{graph_id}', +},{ + clientCallName: 'client.graphs.addFileToGraph', + fullyQualifiedName: 'graphs.addFileToGraph', + httpMethod: 'post', + httpPath: '/v1/graphs/{graph_id}/file', +},{ + clientCallName: 'client.graphs.question', + fullyQualifiedName: 'graphs.question', + httpMethod: 'post', + httpPath: '/v1/graphs/question', +},{ + clientCallName: 'client.graphs.removeFileFromGraph', + fullyQualifiedName: 'graphs.removeFileFromGraph', + httpMethod: 'delete', + httpPath: '/v1/graphs/{graph_id}/file/{file_id}', +},{ + clientCallName: 'client.files.retrieve', + fullyQualifiedName: 'files.retrieve', + httpMethod: 'get', + httpPath: '/v1/files/{file_id}', +},{ + clientCallName: 'client.files.list', + fullyQualifiedName: 'files.list', + httpMethod: 'get', + httpPath: '/v1/files', +},{ + clientCallName: 'client.files.delete', + fullyQualifiedName: 'files.delete', + httpMethod: 'delete', + httpPath: '/v1/files/{file_id}', +},{ + clientCallName: 'client.files.download', + fullyQualifiedName: 'files.download', + httpMethod: 'get', + httpPath: '/v1/files/{file_id}/download', +},{ + clientCallName: 'client.files.retry', + fullyQualifiedName: 'files.retry', + httpMethod: 'post', + httpPath: '/v1/files/retry', +},{ + clientCallName: 'client.files.upload', + fullyQualifiedName: 'files.upload', + httpMethod: 'post', + httpPath: '/v1/files', +},{ + clientCallName: 'client.tools.parsePdf', + fullyQualifiedName: 'tools.parsePdf', + httpMethod: 'post', + httpPath: '/v1/tools/pdf-parser/{file_id}', +},{ + clientCallName: 'client.tools.webSearch', + fullyQualifiedName: 'tools.webSearch', + httpMethod: 'post', + httpPath: '/v1/tools/web-search', +},{ + clientCallName: 'client.translation.translate', + fullyQualifiedName: 'translation.translate', + httpMethod: 'post', + httpPath: '/v1/translation', +},{ + clientCallName: 'client.vision.analyze', + fullyQualifiedName: 'vision.analyze', + httpMethod: 'post', + httpPath: '/v1/vision', +}]; function allowedMethodsForCodeTool(options: McpOptions | undefined): SdkMethod[] | undefined { if (!options) { @@ -205,9 +174,9 @@ function allowedMethodsForCodeTool(options: McpOptions | undefined): SdkMethod[] if (options.codeAllowHttpGets) { // Add all methods that map to an HTTP GET - sdkMethods - .filter((method) => method.httpMethod === 'get') - .forEach((method) => allowedMethodsSet.add(method)); + sdkMethods.filter((method) => method.httpMethod === 'get').forEach( + (method) => allowedMethodsSet.add(method) + ); } if (options.codeAllowedMethods) { @@ -216,15 +185,13 @@ function allowedMethodsForCodeTool(options: McpOptions | undefined): SdkMethod[] try { return new RegExp(pattern); } catch (e) { - throw new Error( - `Invalid regex pattern for allowed method: "${pattern}": ${e instanceof Error ? e.message : e}`, - ); + throw new Error(`Invalid regex pattern for allowed method: "${pattern}": ${e instanceof Error ? e.message : e}`); } }); - sdkMethods - .filter((method) => allowedRegexps.some((regexp) => regexp.test(method.fullyQualifiedName))) - .forEach((method) => allowedMethodsSet.add(method)); + sdkMethods.filter((method) => + allowedRegexps.some((regexp) => regexp.test(method.fullyQualifiedName)) + ).forEach((method) => allowedMethodsSet.add(method)); } allowedMethods = Array.from(allowedMethodsSet); @@ -239,14 +206,12 @@ function allowedMethodsForCodeTool(options: McpOptions | undefined): SdkMethod[] try { return new RegExp(pattern); } catch (e) { - throw new Error( - `Invalid regex pattern for blocked method: "${pattern}": ${e instanceof Error ? e.message : e}`, - ); + throw new Error(`Invalid regex pattern for blocked method: "${pattern}": ${e instanceof Error ? e.message : e}`); } }); - allowedMethods = allowedMethods.filter( - (method) => !blockedRegexps.some((regexp) => regexp.test(method.fullyQualifiedName)), + allowedMethods = allowedMethods.filter((method) => + !blockedRegexps.some((regexp) => regexp.test(method.fullyQualifiedName)) ); } diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts index f1518764..873ab8e8 100644 --- a/packages/mcp-server/src/options.ts +++ b/packages/mcp-server/src/options.ts @@ -31,46 +31,31 @@ export type McpCodeExecutionMode = 'stainless-sandbox' | 'local'; export function parseCLIOptions(): CLIOptions { const opts = yargs(hideBin(process.argv)) - .option('code-allow-http-gets', { - type: 'boolean', - description: - 'Allow all code tool methods that map to HTTP GET operations. If all code-allow-* flags are unset, then everything is allowed.', - }) + .option('code-allow-http-gets', { type: 'boolean', description: 'Allow all code tool methods that map to HTTP GET operations. If all code-allow-* flags are unset, then everything is allowed.' }) .option('code-allowed-methods', { type: 'string', array: true, - description: - 'Methods to explicitly allow for code tool. Evaluated as regular expressions against method fully qualified names. If all code-allow-* flags are unset, then everything is allowed.', + description: 'Methods to explicitly allow for code tool. Evaluated as regular expressions against method fully qualified names. If all code-allow-* flags are unset, then everything is allowed.', }) .option('code-blocked-methods', { type: 'string', array: true, - description: - 'Methods to explicitly block for code tool. Evaluated as regular expressions against method fully qualified names. If all code-allow-* flags are unset, then everything is allowed.', + description: 'Methods to explicitly block for code tool. Evaluated as regular expressions against method fully qualified names. If all code-allow-* flags are unset, then everything is allowed.', }) .option('code-execution-mode', { type: 'string', choices: ['stainless-sandbox', 'local'], default: 'stainless-sandbox', - description: - "Where to run code execution in code tool; 'stainless-sandbox' will execute code in Stainless-hosted sandboxes whereas 'local' will execute code locally on the MCP server machine.", - }) - .option('custom-instructions-path', { - type: 'string', - description: 'Path to custom instructions for the MCP server', + description: 'Where to run code execution in code tool; \'stainless-sandbox\' will execute code in Stainless-hosted sandboxes whereas \'local\' will execute code locally on the MCP server machine.', }) + .option('custom-instructions-path', { type: 'string', description: 'Path to custom instructions for the MCP server' }) .option('debug', { type: 'boolean', description: 'Enable debug logging' }) - .option('docs-dir', { - type: 'string', - description: - 'Path to a directory of local documentation files (markdown/JSON) to include in local docs search.', - }) + .option('docs-dir', { type: 'string', description: 'Path to a directory of local documentation files (markdown/JSON) to include in local docs search.' }) .option('docs-search-mode', { type: 'string', choices: ['stainless-api', 'local'], default: 'stainless-api', - description: - "Where to search documentation; 'stainless-api' uses the Stainless-hosted search API whereas 'local' uses an in-memory search index built from embedded SDK method data and optional local docs files.", + description: 'Where to search documentation; \'stainless-api\' uses the Stainless-hosted search API whereas \'local\' uses an in-memory search index built from embedded SDK method data and optional local docs files.', }) .option('log-format', { type: 'string', @@ -92,8 +77,7 @@ export function parseCLIOptions(): CLIOptions { .option('stainless-api-key', { type: 'string', default: readEnv('STAINLESS_API_KEY'), - description: - 'API key for Stainless. Used to authenticate requests to Stainless-hosted tools endpoints.', + description: 'API key for Stainless. Used to authenticate requests to Stainless-hosted tools endpoints.', }) .option('tools', { type: 'string', @@ -114,18 +98,15 @@ export function parseCLIOptions(): CLIOptions { const argv = opts.parseSync(); const shouldIncludeToolType = (toolType: 'code' | 'docs') => - argv.noTools?.includes(toolType) ? false - : argv.tools?.includes(toolType) ? true - : undefined; + argv.noTools?.includes(toolType) ? false + : argv.tools?.includes(toolType) ? true + : undefined; const includeCodeTool = shouldIncludeToolType('code'); const includeDocsTools = shouldIncludeToolType('docs'); const transport = argv.transport as 'stdio' | 'http'; - const logFormat = - argv.logFormat ? (argv.logFormat as 'json' | 'pretty') - : process.stderr.isTTY ? 'pretty' - : 'json'; + const logFormat = argv.logFormat ? argv.logFormat as 'json' | 'pretty' : (process.stderr.isTTY ? 'pretty' : 'json'); return { ...(includeCodeTool !== undefined && { includeCodeTool }), @@ -166,8 +147,8 @@ export function parseQueryOptions(defaultOptions: McpOptions, query: unknown): M const queryOptions = QueryOptions.parse(queryObject); let codeTool: boolean | undefined = - queryOptions.no_tools && queryOptions.no_tools?.includes('code') ? false - : queryOptions.tools?.includes('code') ? true + queryOptions.no_tools && queryOptions.no_tools?.includes("code") ? false + : queryOptions.tools?.includes("code") ? true : defaultOptions.includeCodeTool; let docsTools: boolean | undefined = diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index f6b107b8..e2aa3207 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -3,9 +3,7 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { - CallToolRequestSchema, - ListToolsRequestSchema, - SetLevelRequestSchema, + CallToolRequestSchema,ListToolsRequestSchema,SetLevelRequestSchema } from '@modelcontextprotocol/sdk/types.js'; import { ClientOptions } from 'writer-sdk'; import Writer from 'writer-sdk'; @@ -16,25 +14,24 @@ import { LocalDocsSearch } from './local-docs-search'; import { getInstructions } from './instructions'; import { McpOptions } from './options'; import { blockedMethodsForCodeTool } from './methods'; -import { HandlerFunction, McpRequestContext, ToolCallResult, McpTool } from './types'; +import { HandlerFunction, McpRequestContext, ToolCallResult, McpTool } from "./types" export const newMcpServer = async ({ stainlessApiKey, customInstructionsPath, }: { - stainlessApiKey?: string | undefined; - customInstructionsPath?: string | undefined; -}) => - new McpServer( - { - name: 'writer_sdk_api', - version: '3.0.0-rc.1', - }, - { - instructions: await getInstructions({ stainlessApiKey, customInstructionsPath }), - capabilities: { tools: {}, logging: {} }, - }, - ); + stainlessApiKey?: string | undefined, + customInstructionsPath?: string | undefined, +}) => new McpServer( + { + name: 'writer_sdk_api', + version: '3.0.0-rc.1', + }, + { + instructions: await getInstructions({stainlessApiKey, customInstructionsPath}), + capabilities: { tools: {}, logging: {} }, + } +); /** * Initializes the provided MCP Server with the given tools and handlers. @@ -56,15 +53,15 @@ export async function initMcpServer(params: { (message: string, ...rest: unknown[]) => { void server.sendLoggingMessage({ level, - data: { message, rest }, + data: {message, rest}, }); - }; + } const logger = { - debug: logAtLevel('debug'), - info: logAtLevel('info'), - warn: logAtLevel('warning'), - error: logAtLevel('error'), - }; + debug: logAtLevel("debug"), + info: logAtLevel("info"), + warn: logAtLevel("warning"), + error: logAtLevel("error"), + } if (params.mcpOptions?.docsSearchMode === 'local') { const docsDir = params.mcpOptions?.docsDir; @@ -81,13 +78,14 @@ export async function initMcpServer(params: { if (!_client) { try { _client = new Writer({ - logger, - ...params.clientOptions, - defaultHeaders: { - ...params.clientOptions?.defaultHeaders, - 'X-Stainless-MCP': 'true', - }, - }); + + logger, + ...params.clientOptions, + defaultHeaders: { + ...params.clientOptions?.defaultHeaders, + 'X-Stainless-MCP': 'true', + }, +}); if (_logLevel) { _client = _client.withOptions({ logLevel: _logLevel }); } @@ -120,12 +118,10 @@ export async function initMcpServer(params: { client = getClient(); } catch (error) { return { - content: [ - { - type: 'text' as const, - text: `Failed to initialize client: ${error instanceof Error ? error.message : String(error)}`, - }, - ], + content: [{ + type: 'text' as const, + text: `Failed to initialize client: ${error instanceof Error ? error.message : String(error)}`, + }], isError: true, }; } @@ -175,16 +171,17 @@ export async function initMcpServer(params: { /** * Selects the tools to include in the MCP Server based on the provided options. */ -export function selectTools(options?: McpOptions): McpTool[] { +export function selectTools( + options?: McpOptions +): McpTool[] { + const includedTools = []; if (options?.includeCodeTool ?? true) { - includedTools.push( - codeTool({ - blockedMethods: blockedMethodsForCodeTool(options), - codeExecutionMode: options?.codeExecutionMode ?? 'stainless-sandbox', - }), - ); + includedTools.push(codeTool({ + blockedMethods: blockedMethodsForCodeTool(options), + codeExecutionMode: options?.codeExecutionMode ?? 'stainless-sandbox', + })); } if (options?.includeDocsTools ?? true) { includedTools.push(docsSearchTool); @@ -195,14 +192,13 @@ export function selectTools(options?: McpOptions): McpTool[] { /** * Runs the provided handler with the given client and arguments. */ -export async function executeHandler({ - handler, - reqContext, - args, -}: { - handler: HandlerFunction; - reqContext: McpRequestContext; - args: Record | undefined; -}): Promise { - return await handler({ reqContext, args: args || {} }); +export async function executeHandler( + {handler, reqContext, args}: + { + handler: HandlerFunction; + reqContext: McpRequestContext; + args: Record | undefined; + } +): Promise { + return await handler({reqContext, args: args || {}}); } diff --git a/packages/mcp-server/src/types.ts b/packages/mcp-server/src/types.ts index 2c730de7..52a66b00 100644 --- a/packages/mcp-server/src/types.ts +++ b/packages/mcp-server/src/types.ts @@ -4,43 +4,41 @@ import Writer from 'writer-sdk'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; type TextContentBlock = { - type: 'text'; - text: string; -}; + type: "text", + text: string +} type ImageContentBlock = { - type: 'image'; - data: string; - mimeType: string; -}; + type: "image", + data: string, + mimeType: string +} type AudioContentBlock = { - type: 'audio'; - data: string; - mimeType: string; -}; + type: "audio", + data: string, + mimeType: string +} type ResourceContentBlock = { - type: 'resource'; - resource: - | { - uri: string; - mimeType: string; - text: string; - } - | { - uri: string; - mimeType: string; - blob: string; - }; -}; + type: "resource", + resource: { + uri: string, + mimeType: string, + text: string + } | { + uri: string, + mimeType: string, + blob: string + } +} export type ContentBlock = TextContentBlock | ImageContentBlock | AudioContentBlock | ResourceContentBlock; export type ToolCallResult = { content: ContentBlock[]; isError?: boolean; -}; +} export type McpRequestContext = { client: Writer; @@ -48,7 +46,7 @@ export type McpRequestContext = { upstreamClientEnvs?: Record | undefined; mcpSessionId?: string | undefined; mcpClientInfo?: { name: string; version: string } | undefined; -}; +} export type HandlerFunction = ({ reqContext, @@ -58,7 +56,9 @@ export type HandlerFunction = ({ args: Record | undefined; }) => Promise; -export function asTextContentResult(result: unknown): ToolCallResult { +export function asTextContentResult( + result: unknown, +): ToolCallResult { return { content: [ { @@ -69,18 +69,24 @@ export function asTextContentResult(result: unknown): ToolCallResult { }; } -export async function asBinaryContentResult(response: Response): Promise { +export async function asBinaryContentResult( + response: Response, +): Promise { const blob = await response.blob(); const mimeType = blob.type; const data = Buffer.from(await blob.arrayBuffer()).toString('base64'); if (mimeType.startsWith('image/')) { return { - content: [{ type: 'image', mimeType, data }], - }; + content: [ + {type: 'image', mimeType, data} + ] + } } else if (mimeType.startsWith('audio/')) { return { - content: [{ type: 'audio', mimeType, data }], - }; + content: [ + {type: 'audio', mimeType, data} + ] + } } else { return { content: [ @@ -98,7 +104,9 @@ export async function asBinaryContentResult(response: Response): Promise Running prettier --write" -# format things eslint didn't -PRETTIER_FILES="$(grep '\.\(js\|json\)$' "$FILE_LIST" || true)" +PRETTIER_FILES="$(grep '\.\([mc]?tsx?\|[mc]?jsx?\|json\)$' "$FILE_LIST" || true)" if ! [ -z "$PRETTIER_FILES" ]; then echo "$PRETTIER_FILES" | xargs ./node_modules/.bin/prettier \ - --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern \ - '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' + --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern fi diff --git a/scripts/format b/scripts/format index 7a756401..b1b2c17a 100755 --- a/scripts/format +++ b/scripts/format @@ -8,5 +8,4 @@ echo "==> Running eslint --fix" ./node_modules/.bin/eslint --fix . echo "==> Running prettier --write" -# format things eslint didn't -./node_modules/.bin/prettier --write --cache --cache-strategy metadata . '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' +./node_modules/.bin/prettier --write --cache --cache-strategy metadata . diff --git a/scripts/lint b/scripts/lint index 3ffb78a6..1f532548 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,6 +4,9 @@ set -e cd "$(dirname "$0")/.." +echo "==> Running prettier --check" +./node_modules/.bin/prettier --check . + echo "==> Running eslint" ./node_modules/.bin/eslint . diff --git a/src/api-promise.ts b/src/api-promise.ts index 8c775ee6..4e701286 100644 --- a/src/api-promise.ts +++ b/src/api-promise.ts @@ -1,2 +1,2 @@ /** @deprecated Import from ./core/api-promise instead */ -export * from './core/api-promise'; +export * from "./core/api-promise" \ No newline at end of file diff --git a/src/client.ts b/src/client.ts index d43b78e2..ef491d61 100644 --- a/src/client.ts +++ b/src/client.ts @@ -15,104 +15,24 @@ import { stringifyQuery } from './internal/utils/query'; import { VERSION } from './version'; import * as Errors from './core/error'; import * as Pagination from './core/pagination'; -import { - AbstractPage, - type ApplicationJobsOffsetParams, - ApplicationJobsOffsetResponse, - type CursorPageParams, - CursorPageResponse, -} from './core/pagination'; +import { AbstractPage, type ApplicationJobsOffsetParams, ApplicationJobsOffsetResponse, type CursorPageParams, CursorPageResponse } from './core/pagination'; import * as Uploads from './core/uploads'; import * as API from './resources/index'; import { APIPromise } from './core/api-promise'; -import { - Chat, - ChatChatParams, - ChatChatParamsNonStreaming, - ChatChatParamsStreaming, - ChatCompletion, - ChatCompletionChoice, - ChatCompletionChunk, - ChatCompletionMessage, - ChatCompletionParams, - ChatCompletionUsage, -} from './resources/chat'; -import { - Completion, - CompletionChunk, - CompletionCreateParams, - CompletionCreateParamsNonStreaming, - CompletionCreateParamsStreaming, - CompletionParams, - Completions, -} from './resources/completions'; -import { - File, - FileDeleteResponse, - FileListParams, - FileRetryParams, - FileRetryResponse, - FileUploadParams, - Files, - FilesCursorPage, -} from './resources/files'; -import { - Graph, - GraphAddFileToGraphParams, - GraphCreateParams, - GraphCreateResponse, - GraphDeleteResponse, - GraphListParams, - GraphQuestionParams, - GraphQuestionParamsNonStreaming, - GraphQuestionParamsStreaming, - GraphRemoveFileFromGraphParams, - GraphRemoveFileFromGraphResponse, - GraphUpdateParams, - GraphUpdateResponse, - Graphs, - GraphsCursorPage, - Question, - QuestionResponseChunk, -} from './resources/graphs'; +import { Chat, ChatChatParams, ChatChatParamsNonStreaming, ChatChatParamsStreaming, ChatCompletion, ChatCompletionChoice, ChatCompletionChunk, ChatCompletionMessage, ChatCompletionParams, ChatCompletionUsage } from './resources/chat'; +import { Completion, CompletionChunk, CompletionCreateParams, CompletionCreateParamsNonStreaming, CompletionCreateParamsStreaming, CompletionParams, Completions } from './resources/completions'; +import { File, FileDeleteResponse, FileListParams, FileRetryParams, FileRetryResponse, FileUploadParams, Files, FilesCursorPage } from './resources/files'; +import { Graph, GraphAddFileToGraphParams, GraphCreateParams, GraphCreateResponse, GraphDeleteResponse, GraphListParams, GraphQuestionParams, GraphQuestionParamsNonStreaming, GraphQuestionParamsStreaming, GraphRemoveFileFromGraphParams, GraphRemoveFileFromGraphResponse, GraphUpdateParams, GraphUpdateResponse, Graphs, GraphsCursorPage, Question, QuestionResponseChunk } from './resources/graphs'; import { ModelListResponse, Models } from './resources/models'; -import { - ToolParsePdfParams, - ToolParsePdfResponse, - ToolWebSearchParams, - ToolWebSearchResponse, - Tools, -} from './resources/tools'; -import { - Translation, - TranslationRequest, - TranslationResponse, - TranslationTranslateParams, -} from './resources/translation'; +import { ToolParsePdfParams, ToolParsePdfResponse, ToolWebSearchParams, ToolWebSearchResponse, Tools } from './resources/tools'; +import { Translation, TranslationRequest, TranslationResponse, TranslationTranslateParams } from './resources/translation'; import { Vision, VisionAnalyzeParams, VisionRequest, VisionResponse } from './resources/vision'; -import { - ApplicationGenerateContentChunk, - ApplicationGenerateContentParams, - ApplicationGenerateContentParamsNonStreaming, - ApplicationGenerateContentParamsStreaming, - ApplicationGenerateContentResponse, - ApplicationListParams, - ApplicationListResponse, - ApplicationListResponsesCursorPage, - ApplicationRetrieveResponse, - Applications, -} from './resources/applications/applications'; +import { ApplicationGenerateContentChunk, ApplicationGenerateContentParams, ApplicationGenerateContentParamsNonStreaming, ApplicationGenerateContentParamsStreaming, ApplicationGenerateContentResponse, ApplicationListParams, ApplicationListResponse, ApplicationListResponsesCursorPage, ApplicationRetrieveResponse, Applications } from './resources/applications/applications'; import { type Fetch } from './internal/builtin-types'; import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers'; import { FinalRequestOptions, RequestOptions } from './internal/request-options'; import { readEnv } from './internal/utils/env'; -import { - type LogLevel, - type Logger, - formatRequestDetails, - loggerFor, - parseLogLevel, -} from './internal/utils/log'; +import { type LogLevel, type Logger, formatRequestDetails, loggerFor, parseLogLevel } from './internal/utils/log'; import { isEmptyObj } from './internal/utils/values'; export interface ClientOptions { @@ -191,7 +111,7 @@ export interface ClientOptions { } /** - * API Client for interfacing with the Writer API. + * API Client for interfacing with the Writer API. */ export class Writer { apiKey: string; @@ -227,7 +147,7 @@ export class Writer { }: ClientOptions = {}) { if (apiKey === undefined) { throw new Errors.WriterError( - "The WRITER_API_KEY environment variable is missing or empty; either provide it, or instantiate the Writer client with an apiKey option, like new Writer({ apiKey: 'My API Key' }).", + 'The WRITER_API_KEY environment variable is missing or empty; either provide it, or instantiate the Writer client with an apiKey option, like new Writer({ apiKey: \'My API Key\' }).' ); } @@ -243,10 +163,7 @@ export class Writer { const defaultLogLevel = 'warn'; // Set default logLevel early so that we can log a warning in parseLogLevel. this.logLevel = defaultLogLevel; - this.logLevel = - parseLogLevel(options.logLevel, 'ClientOptions.logLevel', this) ?? - parseLogLevel(readEnv('WRITER_LOG'), "process.env['WRITER_LOG']", this) ?? - defaultLogLevel; + this.logLevel = parseLogLevel(options.logLevel, 'ClientOptions.logLevel', this) ?? parseLogLevel(readEnv('WRITER_LOG'), 'process.env[\'WRITER_LOG\']', this) ?? defaultLogLevel; this.fetchOptions = options.fetchOptions; this.maxRetries = options.maxRetries ?? 7; this.fetch = options.fetch ?? Shims.getDefaultFetch(); @@ -271,7 +188,7 @@ export class Writer { fetch: this.fetch, fetchOptions: this.fetchOptions, apiKey: this.apiKey, - ...options, + ...options }); return client; } @@ -284,7 +201,7 @@ export class Writer { } protected defaultQuery(): Record | undefined { - return this._options.defaultQuery; + return this._options.defaultQuery } protected validateHeaders({ values, nulls }: NullableHeaders) { @@ -319,11 +236,7 @@ export class Writer { return Errors.APIError.generate(status, error, message, headers); } - buildURL( - path: string, - query: Record | null | undefined, - defaultBaseURL?: string | undefined, - ): string { + buildURL(path: string, query: Record | null | undefined, defaultBaseURL?: string | undefined): string { const baseURL = (!this.#baseURLOverridden() && defaultBaseURL) || this.baseURL; const url = isAbsoluteURL(path) ? @@ -411,9 +324,7 @@ export class Writer { await this.prepareOptions(options); - const { req, url, timeout } = await this.buildRequest(options, { - retryCount: maxRetries - retriesRemaining, - }); + const { req, url, timeout } = await this.buildRequest(options, { retryCount: maxRetries - retriesRemaining }); await this.prepareRequest(req, { url, options }); @@ -422,16 +333,7 @@ export class Writer { const retryLogStr = retryOfRequestLogID === undefined ? '' : `, retryOf: ${retryOfRequestLogID}`; const startTime = Date.now(); - loggerFor(this).debug( - `[${requestLogID}] sending request`, - formatRequestDetails({ - retryOfRequestLogID, - method: options.method, - url, - options, - headers: req.headers, - }), - ); + loggerFor(this).debug(`[${requestLogID}] sending request`, formatRequestDetails({ retryOfRequestLogID, method: options.method, url, options, headers: req.headers })); if (options.signal?.aborted) { throw new Errors.APIUserAbortError(); @@ -450,45 +352,21 @@ export class Writer { // deno throws "TypeError: error sending request for url (https://example/): client error (Connect): tcp connect error: Operation timed out (os error 60): Operation timed out (os error 60)" // undici throws "TypeError: fetch failed" with cause "ConnectTimeoutError: Connect Timeout Error (attempted address: example:443, timeout: 1ms)" // others do not provide enough information to distinguish timeouts from other connection errors - const isTimeout = - isAbortError(response) || - /timed? ?out/i.test(String(response) + ('cause' in response ? String(response.cause) : '')); + const isTimeout = isAbortError(response) || /timed? ?out/i.test(String(response) + ('cause' in response ? String(response.cause) : '')) if (retriesRemaining) { - loggerFor(this).info( - `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - ${retryMessage}`, - ); - loggerFor(this).debug( - `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (${retryMessage})`, - formatRequestDetails({ - retryOfRequestLogID, - url, - durationMs: headersTime - startTime, - message: response.message, - }), - ); + loggerFor(this).info(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - ${retryMessage}`) + loggerFor(this).debug(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (${retryMessage})`, formatRequestDetails({ retryOfRequestLogID, url, durationMs: headersTime - startTime, message: response.message })); return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID); } - loggerFor(this).info( - `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - error; no more retries left`, - ); - loggerFor(this).debug( - `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (error; no more retries left)`, - formatRequestDetails({ - retryOfRequestLogID, - url, - durationMs: headersTime - startTime, - message: response.message, - }), - ); + loggerFor(this).info(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - error; no more retries left`) + loggerFor(this).debug(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (error; no more retries left)`, formatRequestDetails({ retryOfRequestLogID, url, durationMs: headersTime - startTime, message: response.message })); if (isTimeout) { throw new Errors.APIConnectionTimeoutError(); } throw new Errors.APIConnectionError({ cause: response }); } - const responseInfo = `[${requestLogID}${retryLogStr}] ${req.method} ${url} ${ - response.ok ? 'succeeded' : 'failed' - } with status ${response.status} in ${headersTime - startTime}ms`; + const responseInfo = `[${requestLogID}${retryLogStr}] ${req.method} ${url} ${response.ok ? 'succeeded' : 'failed'} with status ${response.status} in ${headersTime - startTime}ms`; if (!response.ok) { const shouldRetry = await this.shouldRetry(response); @@ -497,60 +375,27 @@ export class Writer { // We don't need the body of this response. await Shims.CancelReadableStream(response.body); - loggerFor(this).info(`${responseInfo} - ${retryMessage}`); - loggerFor(this).debug( - `[${requestLogID}] response error (${retryMessage})`, - formatRequestDetails({ - retryOfRequestLogID, - url: response.url, - status: response.status, - headers: response.headers, - durationMs: headersTime - startTime, - }), - ); - return this.retryRequest( - options, - retriesRemaining, - retryOfRequestLogID ?? requestLogID, - response.headers, - ); + loggerFor(this).info(`${responseInfo} - ${retryMessage}`) + loggerFor(this).debug(`[${requestLogID}] response error (${retryMessage})`, formatRequestDetails({ retryOfRequestLogID, url: response.url, status: response.status, headers: response.headers, durationMs: headersTime - startTime })); + return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID, response.headers); } const retryMessage = shouldRetry ? `error; no more retries left` : `error; not retryable`; - loggerFor(this).info(`${responseInfo} - ${retryMessage}`); + loggerFor(this).info(`${responseInfo} - ${retryMessage}`) const errText = await response.text().catch((err: any) => castToError(err).message); const errJSON = safeJSON(errText) as any; const errMessage = errJSON ? undefined : errText; - loggerFor(this).debug( - `[${requestLogID}] response error (${retryMessage})`, - formatRequestDetails({ - retryOfRequestLogID, - url: response.url, - status: response.status, - headers: response.headers, - message: errMessage, - durationMs: Date.now() - startTime, - }), - ); + loggerFor(this).debug(`[${requestLogID}] response error (${retryMessage})`, formatRequestDetails({ retryOfRequestLogID, url: response.url, status: response.status, headers: response.headers, message: errMessage, durationMs: Date.now() - startTime })); const err = this.makeStatusError(response.status, errJSON, errMessage, response.headers); throw err; } - loggerFor(this).info(responseInfo); - loggerFor(this).debug( - `[${requestLogID}] response start`, - formatRequestDetails({ - retryOfRequestLogID, - url: response.url, - status: response.status, - headers: response.headers, - durationMs: headersTime - startTime, - }), - ); + loggerFor(this).info(responseInfo) + loggerFor(this).debug(`[${requestLogID}] response start`, formatRequestDetails({ retryOfRequestLogID, url: response.url, status: response.status, headers: response.headers, durationMs: headersTime - startTime })); return { response, options, controller, requestLogID, retryOfRequestLogID, startTime }; } @@ -568,10 +413,7 @@ export class Writer { ); } - requestAPIList< - Item = unknown, - PageClass extends Pagination.AbstractPage = Pagination.AbstractPage, - >( + requestAPIList = Pagination.AbstractPage>( Page: new (...args: ConstructorParameters) => PageClass, options: PromiseOrValue, ): Pagination.PagePromise { @@ -591,9 +433,7 @@ export class Writer { const timeout = setTimeout(abort, ms); - const isReadableBody = - ((globalThis as any).ReadableStream && options.body instanceof (globalThis as any).ReadableStream) || - (typeof options.body === 'object' && options.body !== null && Symbol.asyncIterator in options.body); + const isReadableBody = ((globalThis as any).ReadableStream && options.body instanceof (globalThis as any).ReadableStream) || (typeof options.body === "object" && options.body !== null && Symbol.asyncIterator in options.body); const fetchOptions: RequestInit = { signal: controller.signal as any, @@ -608,6 +448,7 @@ export class Writer { } try { + // use undefined this binding; fetch errors if bound to something else in browser/cloudflare return await this.fetch.call(undefined, url, fetchOptions); } finally { @@ -708,12 +549,11 @@ export class Writer { const req: FinalizedRequestInit = { method, headers: reqHeaders, - ...(options.signal && { signal: options.signal }), - ...((globalThis as any).ReadableStream && - body instanceof (globalThis as any).ReadableStream && { duplex: 'half' }), + ...(options.signal && { signal: options.signal}), + ...((globalThis as any).ReadableStream && body instanceof (globalThis as any).ReadableStream && { duplex: "half" }), ...(body && { body }), - ...((this.fetchOptions as any) ?? {}), - ...((options.fetchOptions as any) ?? {}), + ...(this.fetchOptions as any ?? {}), + ...(options.fetchOptions as any ?? {}), }; return { req, url, timeout: options.timeout }; @@ -738,17 +578,15 @@ export class Writer { const headers = buildHeaders([ idempotencyHeaders, - { - Accept: 'application/json', - 'User-Agent': this.getUserAgent(), - 'X-Stainless-Retry-Count': String(retryCount), - ...(options.timeout ? { 'X-Stainless-Timeout': String(Math.trunc(options.timeout / 1000)) } : {}), - ...getPlatformHeaders(), - }, + {Accept: 'application/json', + 'User-Agent': this.getUserAgent(), + 'X-Stainless-Retry-Count': String(retryCount), + ...(options.timeout ? { 'X-Stainless-Timeout': String(Math.trunc(options.timeout / 1000)) } : {}), + ...getPlatformHeaders()}, await this.authHeaders(options), this._options.defaultHeaders, bodyHeaders, - options.headers, + options.headers ]); this.validateHeaders(headers); @@ -775,9 +613,11 @@ export class Writer { ArrayBuffer.isView(body) || body instanceof ArrayBuffer || body instanceof DataView || - (typeof body === 'string' && + ( + typeof body === 'string' && // Preserve legacy string encoding behavior for now - headers.values.has('content-type')) || + headers.values.has('content-type') + ) || // `Blob` is superset of `File` ((globalThis as any).Blob && body instanceof (globalThis as any).Blob) || // `FormData` -> `multipart/form-data` @@ -808,7 +648,7 @@ export class Writer { } static Writer = this; - static DEFAULT_TIMEOUT = 180000; // 3 minutes + static DEFAULT_TIMEOUT = 180000 // 3 minutes static WriterError = Errors.WriterError; static APIError = Errors.APIError; @@ -848,119 +688,125 @@ Writer.Translation = Translation; Writer.Vision = Vision; export declare namespace Writer { - export type RequestOptions = Opts.RequestOptions; - - export import CursorPage = Pagination.CursorPage; - export { type CursorPageParams as CursorPageParams, type CursorPageResponse as CursorPageResponse }; - - export import ApplicationJobsOffset = Pagination.ApplicationJobsOffset; - export { - type ApplicationJobsOffsetParams as ApplicationJobsOffsetParams, - type ApplicationJobsOffsetResponse as ApplicationJobsOffsetResponse, - }; - - export { - Applications as Applications, - type ApplicationGenerateContentChunk as ApplicationGenerateContentChunk, - type ApplicationGenerateContentResponse as ApplicationGenerateContentResponse, - type ApplicationRetrieveResponse as ApplicationRetrieveResponse, - type ApplicationListResponse as ApplicationListResponse, - type ApplicationListResponsesCursorPage as ApplicationListResponsesCursorPage, - type ApplicationListParams as ApplicationListParams, - type ApplicationGenerateContentParams as ApplicationGenerateContentParams, - type ApplicationGenerateContentParamsNonStreaming as ApplicationGenerateContentParamsNonStreaming, - type ApplicationGenerateContentParamsStreaming as ApplicationGenerateContentParamsStreaming, - }; - - export { - Chat as Chat, - type ChatCompletion as ChatCompletion, - type ChatCompletionChoice as ChatCompletionChoice, - type ChatCompletionChunk as ChatCompletionChunk, - type ChatCompletionMessage as ChatCompletionMessage, - type ChatCompletionParams as ChatCompletionParams, - type ChatCompletionUsage as ChatCompletionUsage, - type ChatChatParams as ChatChatParams, - type ChatChatParamsNonStreaming as ChatChatParamsNonStreaming, - type ChatChatParamsStreaming as ChatChatParamsStreaming, - }; - - export { - Completions as Completions, - type Completion as Completion, - type CompletionChunk as CompletionChunk, - type CompletionParams as CompletionParams, - type CompletionCreateParams as CompletionCreateParams, - type CompletionCreateParamsNonStreaming as CompletionCreateParamsNonStreaming, - type CompletionCreateParamsStreaming as CompletionCreateParamsStreaming, - }; - - export { Models as Models, type ModelListResponse as ModelListResponse }; - - export { - Graphs as Graphs, - type Graph as Graph, - type Question as Question, - type QuestionResponseChunk as QuestionResponseChunk, - type GraphCreateResponse as GraphCreateResponse, - type GraphUpdateResponse as GraphUpdateResponse, - type GraphDeleteResponse as GraphDeleteResponse, - type GraphRemoveFileFromGraphResponse as GraphRemoveFileFromGraphResponse, - type GraphsCursorPage as GraphsCursorPage, - type GraphCreateParams as GraphCreateParams, - type GraphUpdateParams as GraphUpdateParams, - type GraphListParams as GraphListParams, - type GraphAddFileToGraphParams as GraphAddFileToGraphParams, - type GraphQuestionParams as GraphQuestionParams, - type GraphQuestionParamsNonStreaming as GraphQuestionParamsNonStreaming, - type GraphQuestionParamsStreaming as GraphQuestionParamsStreaming, - type GraphRemoveFileFromGraphParams as GraphRemoveFileFromGraphParams, - }; - - export { - Files as Files, - type File as File, - type FileDeleteResponse as FileDeleteResponse, - type FileRetryResponse as FileRetryResponse, - type FilesCursorPage as FilesCursorPage, - type FileListParams as FileListParams, - type FileRetryParams as FileRetryParams, - type FileUploadParams as FileUploadParams, - }; - - export { - Tools as Tools, - type ToolParsePdfResponse as ToolParsePdfResponse, - type ToolWebSearchResponse as ToolWebSearchResponse, - type ToolParsePdfParams as ToolParsePdfParams, - type ToolWebSearchParams as ToolWebSearchParams, - }; - - export { - Translation as Translation, - type TranslationRequest as TranslationRequest, - type TranslationResponse as TranslationResponse, - type TranslationTranslateParams as TranslationTranslateParams, - }; - - export { - Vision as Vision, - type VisionRequest as VisionRequest, - type VisionResponse as VisionResponse, - type VisionAnalyzeParams as VisionAnalyzeParams, - }; - - export type ErrorMessage = API.ErrorMessage; - export type ErrorObject = API.ErrorObject; - export type FunctionDefinition = API.FunctionDefinition; - export type FunctionParams = API.FunctionParams; - export type GraphData = API.GraphData; - export type Logprobs = API.Logprobs; - export type LogprobsToken = API.LogprobsToken; - export type Source = API.Source; - export type ToolCall = API.ToolCall; - export type ToolCallStreaming = API.ToolCallStreaming; - export type ToolChoiceJsonObject = API.ToolChoiceJsonObject; - export type ToolChoiceString = API.ToolChoiceString; - export type ToolParam = API.ToolParam; -} + export type RequestOptions = Opts.RequestOptions; + + export import CursorPage = Pagination.CursorPage; +export { + type CursorPageParams as CursorPageParams, + type CursorPageResponse as CursorPageResponse +}; + +export import ApplicationJobsOffset = Pagination.ApplicationJobsOffset; +export { + type ApplicationJobsOffsetParams as ApplicationJobsOffsetParams, + type ApplicationJobsOffsetResponse as ApplicationJobsOffsetResponse +}; + +export { + Applications as Applications, + type ApplicationGenerateContentChunk as ApplicationGenerateContentChunk, + type ApplicationGenerateContentResponse as ApplicationGenerateContentResponse, + type ApplicationRetrieveResponse as ApplicationRetrieveResponse, + type ApplicationListResponse as ApplicationListResponse, + type ApplicationListResponsesCursorPage as ApplicationListResponsesCursorPage, + type ApplicationListParams as ApplicationListParams, + type ApplicationGenerateContentParams as ApplicationGenerateContentParams, + type ApplicationGenerateContentParamsNonStreaming as ApplicationGenerateContentParamsNonStreaming, + type ApplicationGenerateContentParamsStreaming as ApplicationGenerateContentParamsStreaming +}; + +export { + Chat as Chat, + type ChatCompletion as ChatCompletion, + type ChatCompletionChoice as ChatCompletionChoice, + type ChatCompletionChunk as ChatCompletionChunk, + type ChatCompletionMessage as ChatCompletionMessage, + type ChatCompletionParams as ChatCompletionParams, + type ChatCompletionUsage as ChatCompletionUsage, + type ChatChatParams as ChatChatParams, + type ChatChatParamsNonStreaming as ChatChatParamsNonStreaming, + type ChatChatParamsStreaming as ChatChatParamsStreaming +}; + +export { + Completions as Completions, + type Completion as Completion, + type CompletionChunk as CompletionChunk, + type CompletionParams as CompletionParams, + type CompletionCreateParams as CompletionCreateParams, + type CompletionCreateParamsNonStreaming as CompletionCreateParamsNonStreaming, + type CompletionCreateParamsStreaming as CompletionCreateParamsStreaming +}; + +export { + Models as Models, + type ModelListResponse as ModelListResponse +}; + +export { + Graphs as Graphs, + type Graph as Graph, + type Question as Question, + type QuestionResponseChunk as QuestionResponseChunk, + type GraphCreateResponse as GraphCreateResponse, + type GraphUpdateResponse as GraphUpdateResponse, + type GraphDeleteResponse as GraphDeleteResponse, + type GraphRemoveFileFromGraphResponse as GraphRemoveFileFromGraphResponse, + type GraphsCursorPage as GraphsCursorPage, + type GraphCreateParams as GraphCreateParams, + type GraphUpdateParams as GraphUpdateParams, + type GraphListParams as GraphListParams, + type GraphAddFileToGraphParams as GraphAddFileToGraphParams, + type GraphQuestionParams as GraphQuestionParams, + type GraphQuestionParamsNonStreaming as GraphQuestionParamsNonStreaming, + type GraphQuestionParamsStreaming as GraphQuestionParamsStreaming, + type GraphRemoveFileFromGraphParams as GraphRemoveFileFromGraphParams +}; + +export { + Files as Files, + type File as File, + type FileDeleteResponse as FileDeleteResponse, + type FileRetryResponse as FileRetryResponse, + type FilesCursorPage as FilesCursorPage, + type FileListParams as FileListParams, + type FileRetryParams as FileRetryParams, + type FileUploadParams as FileUploadParams +}; + +export { + Tools as Tools, + type ToolParsePdfResponse as ToolParsePdfResponse, + type ToolWebSearchResponse as ToolWebSearchResponse, + type ToolParsePdfParams as ToolParsePdfParams, + type ToolWebSearchParams as ToolWebSearchParams +}; + +export { + Translation as Translation, + type TranslationRequest as TranslationRequest, + type TranslationResponse as TranslationResponse, + type TranslationTranslateParams as TranslationTranslateParams +}; + +export { + Vision as Vision, + type VisionRequest as VisionRequest, + type VisionResponse as VisionResponse, + type VisionAnalyzeParams as VisionAnalyzeParams +}; + +export type ErrorMessage = API.ErrorMessage; +export type ErrorObject = API.ErrorObject; +export type FunctionDefinition = API.FunctionDefinition; +export type FunctionParams = API.FunctionParams; +export type GraphData = API.GraphData; +export type Logprobs = API.Logprobs; +export type LogprobsToken = API.LogprobsToken; +export type Source = API.Source; +export type ToolCall = API.ToolCall; +export type ToolCallStreaming = API.ToolCallStreaming; +export type ToolChoiceJsonObject = API.ToolChoiceJsonObject; +export type ToolChoiceString = API.ToolChoiceString; +export type ToolParam = API.ToolParam; + } diff --git a/src/core/api-promise.ts b/src/core/api-promise.ts index 1552d0f2..5cfa992c 100644 --- a/src/core/api-promise.ts +++ b/src/core/api-promise.ts @@ -16,10 +16,7 @@ export class APIPromise extends Promise { constructor( client: Writer, private responsePromise: Promise, - private parseResponse: ( - client: Writer, - props: APIResponseProps, - ) => PromiseOrValue = defaultParseResponse, + private parseResponse: (client: Writer, props: APIResponseProps) => PromiseOrValue = defaultParseResponse, ) { super((resolve) => { // this is maybe a bit weird but this has to be a no-op to not implicitly @@ -31,9 +28,7 @@ export class APIPromise extends Promise { } _thenUnwrap(transform: (data: T, props: APIResponseProps) => U): APIPromise { - return new APIPromise(this.#client, this.responsePromise, async (client, props) => - transform(await this.parseResponse(client, props), props), - ); + return new APIPromise(this.#client, this.responsePromise, async (client, props) => transform(await this.parseResponse(client, props), props)); } /** diff --git a/src/core/error.ts b/src/core/error.ts index ddd70d3e..41996f70 100644 --- a/src/core/error.ts +++ b/src/core/error.ts @@ -2,13 +2,10 @@ import { castToError } from '../internal/errors'; -export class WriterError extends Error {} +export class WriterError extends Error { +} -export class APIError< - TStatus extends number | undefined = number | undefined, - THeaders extends Headers | undefined = Headers | undefined, - TError extends Object | undefined = Object | undefined, -> extends WriterError { +export class APIError extends WriterError { /** HTTP status for the response that caused the error */ readonly status: TStatus; /** HTTP headers for the response that caused the error */ @@ -16,6 +13,9 @@ export class APIError< /** JSON body of the response that caused the error */ readonly error: TError; + + ; + constructor(status: TStatus, error: TError, message: string | undefined, headers: THeaders) { super(`${APIError.makeMessage(status, error, message)}`); this.status = status; @@ -26,8 +26,7 @@ export class APIError< private static makeMessage(status: number | undefined, error: any, message: string | undefined) { const msg = error?.message ? - typeof error.message === 'string' ? - error.message + typeof error.message === 'string' ? error.message : JSON.stringify(error.message) : error ? JSON.stringify(error) : message; @@ -44,12 +43,7 @@ export class APIError< return '(no status code or body)'; } - static generate( - status: number | undefined, - errorResponse: Object | undefined, - message: string | undefined, - headers: Headers | undefined, - ): APIError { + static generate(status: number | undefined, errorResponse: Object | undefined, message: string | undefined, headers: Headers | undefined): APIError { if (!status || !headers) { return new APIConnectionError({ message, cause: castToError(errorResponse) }); } @@ -113,21 +107,29 @@ export class APIConnectionTimeoutError extends APIConnectionError { } } -export class BadRequestError extends APIError<400, Headers> {} +export class BadRequestError extends APIError<400, Headers> { +} -export class AuthenticationError extends APIError<401, Headers> {} +export class AuthenticationError extends APIError<401, Headers> { +} -export class PermissionDeniedError extends APIError<403, Headers> {} +export class PermissionDeniedError extends APIError<403, Headers> { +} -export class NotFoundError extends APIError<404, Headers> {} +export class NotFoundError extends APIError<404, Headers> { +} -export class ConflictError extends APIError<409, Headers> {} +export class ConflictError extends APIError<409, Headers> { +} -export class UnprocessableEntityError extends APIError<422, Headers> {} +export class UnprocessableEntityError extends APIError<422, Headers> { +} -export class RateLimitError extends APIError<429, Headers> {} +export class RateLimitError extends APIError<429, Headers> { +} -export class InternalServerError extends APIError {} +export class InternalServerError extends APIError { +} export class LengthFinishReasonError extends WriterError { constructor() { diff --git a/src/core/pagination.ts b/src/core/pagination.ts index 383535e1..266b2c18 100644 --- a/src/core/pagination.ts +++ b/src/core/pagination.ts @@ -87,8 +87,7 @@ export class PagePromise< super( client, request, - async (client, props) => - new Page(client, props.response, await defaultParseResponse(client, props), props.options), + async (client, props) => new Page(client, props.response, await defaultParseResponse(client, props), props.options) ); } @@ -127,20 +126,12 @@ export interface CursorPageParams { before?: string; } -export class CursorPage - extends AbstractPage - implements CursorPageResponse -{ +export class CursorPage extends AbstractPage implements CursorPageResponse { data: Array; has_more: boolean; - constructor( - client: Writer, - response: Response, - body: CursorPageResponse, - options: FinalRequestOptions, - ) { + constructor(client: Writer, response: Response, body: CursorPageResponse, options: FinalRequestOptions) { super(client, response, body, options); this.data = body.data || []; @@ -174,7 +165,7 @@ export class CursorPage }; } - const id = data[0]?.id; + const id = data[0]?.id if (!id) { return null; } @@ -217,22 +208,14 @@ export interface ApplicationJobsOffsetParams { limit?: number; } -export class ApplicationJobsOffset - extends AbstractPage - implements ApplicationJobsOffsetResponse -{ +export class ApplicationJobsOffset extends AbstractPage implements ApplicationJobsOffsetResponse { result: Array; totalCount: number; pagination: ApplicationJobsOffsetResponse.Pagination; - constructor( - client: Writer, - response: Response, - body: ApplicationJobsOffsetResponse, - options: FinalRequestOptions, - ) { + constructor(client: Writer, response: Response, body: ApplicationJobsOffsetResponse, options: FinalRequestOptions) { super(client, response, body, options); this.result = body.result || []; @@ -256,14 +239,14 @@ export class ApplicationJobsOffset if (currentCount < totalCount) { return { - ...this.options, - query: { - ...maybeObj(this.options.query), - offset: currentCount, - }, - }; + ...this.options, + query: { + ...maybeObj(this.options.query), + offset: currentCount, + }, + }; } - return null; + return null } } diff --git a/src/core/streaming.ts b/src/core/streaming.ts index 82383c28..5bdc2abf 100644 --- a/src/core/streaming.ts +++ b/src/core/streaming.ts @@ -9,7 +9,7 @@ import { encodeUTF8 } from '../internal/utils/bytes'; import { loggerFor } from '../internal/utils/log'; import type { Writer } from '../client'; -import { APIError } from './error'; +import { APIError } from './error';; type Bytes = string | ArrayBuffer | Uint8Array | null | undefined; @@ -32,29 +32,29 @@ export class Stream implements AsyncIterable { this.#client = client; } - static fromSSEResponse( - response: Response, - controller: AbortController, - client?: Writer, - ): Stream { + static fromSSEResponse(response: Response, +controller: AbortController, +client?: Writer,): Stream { let consumed = false; const logger = client ? loggerFor(client) : console; async function* iterator(): AsyncIterator { if (consumed) { - throw new WriterError('Cannot iterate over a consumed stream, use `.tee()` to split the stream.'); + throw new WriterError( + 'Cannot iterate over a consumed stream, use `.tee()` to split the stream.', + ); } consumed = true; let done = false; try { for await (const sse of _iterSSEMessages(response, controller)) { if (done) continue; - + if (sse.data.startsWith('[DONE]')) { done = true; continue; } - + if (sse.event === null) { try { yield JSON.parse(sse.data) as Item; @@ -64,10 +64,10 @@ export class Stream implements AsyncIterable { throw e; } } - + if (sse.event === 'error') { throw new APIError(undefined, safeJSON(sse.data) ?? sse.data, undefined, response.headers); - } + }; } done = true; } catch (e) { @@ -111,7 +111,9 @@ export class Stream implements AsyncIterable { async function* iterator(): AsyncIterator { if (consumed) { - throw new WriterError('Cannot iterate over a consumed stream, use `.tee()` to split the stream.'); + throw new WriterError( + 'Cannot iterate over a consumed stream, use `.tee()` to split the stream.', + ); } consumed = true; let done = false; diff --git a/src/error.ts b/src/error.ts index fc55f46c..d0832d34 100644 --- a/src/error.ts +++ b/src/error.ts @@ -1,2 +1,2 @@ /** @deprecated Import from ./core/error instead */ -export * from './core/error'; +export * from "./core/error" \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 188418c8..def542ca 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,18 +6,4 @@ export { type Uploadable, toFile } from './core/uploads'; export { APIPromise } from './core/api-promise'; export { Writer, type ClientOptions } from './client'; export { PagePromise } from './core/pagination'; -export { - WriterError, - APIError, - APIConnectionError, - APIConnectionTimeoutError, - APIUserAbortError, - NotFoundError, - ConflictError, - RateLimitError, - BadRequestError, - AuthenticationError, - InternalServerError, - PermissionDeniedError, - UnprocessableEntityError, -} from './core/error'; +export { WriterError, APIError, APIConnectionError, APIConnectionTimeoutError, APIUserAbortError, NotFoundError, ConflictError, RateLimitError, BadRequestError, AuthenticationError, InternalServerError, PermissionDeniedError, UnprocessableEntityError } from './core/error'; diff --git a/src/internal/builtin-types.ts b/src/internal/builtin-types.ts index c23d3bde..6059d5db 100644 --- a/src/internal/builtin-types.ts +++ b/src/internal/builtin-types.ts @@ -1,20 +1,23 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -export type Fetch = (input: string | URL | Request, init?: RequestInit) => Promise; +export type Fetch = ( + input: string | URL | Request, + init?: RequestInit, +) => Promise /** * An alias to the builtin `RequestInit` type so we can * easily alias it in import statements if there are name clashes. - * - * https://developer.mozilla.org/docs/Web/API/RequestInit + * + * https://developer.mozilla.org/docs/Web/API/RequestInit */ type _RequestInit = RequestInit; /** * An alias to the builtin `Response` type so we can * easily alias it in import statements if there are name clashes. - * - * https://developer.mozilla.org/docs/Web/API/Response + * + * https://developer.mozilla.org/docs/Web/API/Response */ type _Response = Response; @@ -51,15 +54,7 @@ type _Array = Array; */ type _Record = Record; -export type { - _Array as Array, - _BodyInit as BodyInit, - _HeadersInit as HeadersInit, - _Record as Record, - _RequestInfo as RequestInfo, - _RequestInit as RequestInit, - _Response as Response, -}; +export type { _Array as Array, _BodyInit as BodyInit, _HeadersInit as HeadersInit, _Record as Record, _RequestInfo as RequestInfo, _RequestInit as RequestInit, _Response as Response }; /** * A copy of the builtin `EndingType` type as it isn't fully supported in certain diff --git a/src/internal/detect-platform.ts b/src/internal/detect-platform.ts index e82d95c9..394ede88 100644 --- a/src/internal/detect-platform.ts +++ b/src/internal/detect-platform.ts @@ -25,11 +25,7 @@ function getDetectedPlatform(): DetectedPlatform { if (typeof EdgeRuntime !== 'undefined') { return 'edge'; } - if ( - Object.prototype.toString.call( - typeof (globalThis as any).process !== 'undefined' ? (globalThis as any).process : 0, - ) === '[object process]' - ) { + if (Object.prototype.toString.call(typeof (globalThis as any).process !== 'undefined' ? (globalThis as any).process : 0) === '[object process]') { return 'node'; } return 'unknown'; diff --git a/src/internal/errors.ts b/src/internal/errors.ts index 82c7b14d..c14a742b 100644 --- a/src/internal/errors.ts +++ b/src/internal/errors.ts @@ -2,12 +2,12 @@ export function isAbortError(err: unknown) { return ( - typeof err === 'object' && - err !== null && - // Spec-compliant fetch implementations - (('name' in err && (err as any).name === 'AbortError') || + typeof err === 'object' && err !== null && ( + // Spec-compliant fetch implementations + ('name' in err && (err as any).name === 'AbortError') || // Expo fetch - ('message' in err && String((err as any).message).includes('FetchRequestCanceledException'))) + ('message' in err && String((err as any).message).includes('FetchRequestCanceledException')) + ) ); } @@ -24,10 +24,10 @@ export const castToError = (err: any): Error => { if (err.name) error.name = err.name; return error; } - } catch {} + } catch { } try { return new Error(JSON.stringify(err)); - } catch {} + } catch { } } return new Error(err); }; diff --git a/src/internal/headers.ts b/src/internal/headers.ts index c724a9d2..fa2ea2b9 100644 --- a/src/internal/headers.ts +++ b/src/internal/headers.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { isReadonlyArray } from './utils/values'; +import { isReadonlyArray } from "./utils/values"; type HeaderValue = string | undefined | null; export type HeadersLike = @@ -51,7 +51,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator(client: Writer, props: APIResponse const text = await response.text(); return text as unknown as T; })(); - loggerFor(client).debug( - `[${requestLogID}] response parsed`, - formatRequestDetails({ - retryOfRequestLogID, - url: response.url, - status: response.status, - body, - durationMs: Date.now() - startTime, - }), - ); + loggerFor(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails({ retryOfRequestLogID, url: response.url, status: response.status, body, durationMs: Date.now() - startTime })); return body; } diff --git a/src/internal/request-options.ts b/src/internal/request-options.ts index 493c1ce3..4dbdbd18 100644 --- a/src/internal/request-options.ts +++ b/src/internal/request-options.ts @@ -77,11 +77,14 @@ export type RequestOptions = { defaultBaseURL?: string | undefined; __binaryResponse?: boolean | undefined; - __streamClass?: typeof Stream; + __streamClass?: typeof Stream }; export type EncodedContent = { bodyHeaders: HeadersLike; body: BodyInit }; -export type RequestEncoder = (request: { headers: NullableHeaders; body: unknown }) => EncodedContent; +export type RequestEncoder = (request: { + headers: NullableHeaders; + body: unknown; +}) => EncodedContent; export const FallbackEncoder: RequestEncoder = ({ headers, body }) => { return { diff --git a/src/internal/shim-types.ts b/src/internal/shim-types.ts index 8ddf7b0a..accbf576 100644 --- a/src/internal/shim-types.ts +++ b/src/internal/shim-types.ts @@ -19,8 +19,8 @@ type _ConditionalNodeReadableStream = typeof globalThis extends { ReadableStream: any } ? never : _NodeReadableStream; type _ReadableStream = NeverToAny< - | ([0] extends [1 & _DOMReadableStream] ? never : _DOMReadableStream) - | ([0] extends [1 & _ConditionalNodeReadableStream] ? never : _ConditionalNodeReadableStream) + ([0] extends [1 & _DOMReadableStream] ? never : _DOMReadableStream) | + ([0] extends [1 & _ConditionalNodeReadableStream] ? never : _ConditionalNodeReadableStream) >; export type { _ReadableStream as ReadableStream }; diff --git a/src/internal/shims.ts b/src/internal/shims.ts index da6f0097..dfcfbbf0 100644 --- a/src/internal/shims.ts +++ b/src/internal/shims.ts @@ -27,9 +27,7 @@ export function makeReadableStream(...args: ReadableStreamArgs): ReadableStream if (typeof ReadableStream === 'undefined') { // Note: All of the platforms / runtimes we officially support already define // `ReadableStream` as a global, so this should only ever be hit on unsupported runtimes. - throw new Error( - '`ReadableStream` is not defined as a global; You will need to polyfill it, `globalThis.ReadableStream = ReadableStream`', - ); + throw new Error('`ReadableStream` is not defined as a global; You will need to polyfill it, `globalThis.ReadableStream = ReadableStream`'); } return new ReadableStream(...args); diff --git a/src/internal/to-file.ts b/src/internal/to-file.ts index 30eada32..c72a2b41 100644 --- a/src/internal/to-file.ts +++ b/src/internal/to-file.ts @@ -1,4 +1,4 @@ -import { BlobPart, getName, makeFile, isAsyncIterable } from './uploads'; +import { BlobPart, getName, makeFile, isAsyncIterable } from "./uploads"; import type { FilePropertyBag } from './builtin-types'; import { checkFileSupport } from './uploads'; @@ -65,11 +65,8 @@ const isResponseLike = (value: any): value is ResponseLike => typeof value.url === 'string' && typeof value.blob === 'function'; -export type ToFileInput = - | FileLike - | ResponseLike - | Exclude - | AsyncIterable; +export type ToFileInput = FileLike | ResponseLike | Exclude | AsyncIterable; + /** * Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats @@ -119,7 +116,9 @@ export async function toFile( return makeFile(parts, name, options); } -async function getBytes(value: BlobLikePart | AsyncIterable): Promise> { +async function getBytes( + value: BlobLikePart | AsyncIterable, +): Promise> { let parts: Array = []; if ( typeof value === 'string' || @@ -152,3 +151,4 @@ function propsForError(value: unknown): string { const props = Object.getOwnPropertyNames(value); return `; props: [${props.map((p) => `"${p}"`).join(', ')}]`; } + diff --git a/src/internal/types.ts b/src/internal/types.ts index b668dfc0..c45fee32 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -7,40 +7,34 @@ export type KeysEnum = { [P in keyof Required]: true }; export type FinalizedRequestInit = RequestInit & { headers: Headers }; -type NotAny = [0] extends [1 & T] ? never : T; +type NotAny = [0] extends [(1 & T)] ? never : T; /** * Some environments overload the global fetch function, and Parameters only gets the last signature. */ -type OverloadedParameters = - T extends ( - { +type OverloadedParameters = T extends { + (...args: infer A): unknown; + (...args: infer B): unknown; + (...args: infer C): unknown; + (...args: infer D): unknown; +} + ? A | B | C | D + : T extends { (...args: infer A): unknown; (...args: infer B): unknown; (...args: infer C): unknown; - (...args: infer D): unknown; } - ) ? - A | B | C | D - : T extends ( - { - (...args: infer A): unknown; - (...args: infer B): unknown; - (...args: infer C): unknown; - } - ) ? - A | B | C - : T extends ( - { + ? A | B | C + : T extends { (...args: infer A): unknown; (...args: infer B): unknown; } - ) ? - A | B - : T extends (...args: infer A) => unknown ? A + ? A | B + : T extends (...args: infer A) => unknown + ? A : never; -/* eslint-disable */ + /** * These imports attempt to get types from a parent package's dependencies. * Unresolved bare specifiers can trigger [automatic type acquisition][1] in some projects, which @@ -63,19 +57,19 @@ type OverloadedParameters = * * [1]: https://www.typescriptlang.org/tsconfig/#typeAcquisition */ -/** @ts-ignore For users with \@types/node */ +/** @ts-ignore For users with \@types/node */ /* prettier-ignore */ type UndiciTypesRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with undici */ +/** @ts-ignore For users with undici */ /* prettier-ignore */ type UndiciRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with \@types/bun */ +/** @ts-ignore For users with \@types/bun */ /* prettier-ignore */ type BunRequestInit = globalThis.FetchRequestInit; -/** @ts-ignore For users with node-fetch@2 */ +/** @ts-ignore For users with node-fetch@2 */ /* prettier-ignore */ type NodeFetch2RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ +/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ /* prettier-ignore */ type NodeFetch3RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users who use Deno */ +/** @ts-ignore For users who use Deno */ /* prettier-ignore */ type FetchRequestInit = NonNullable[1]>; -/* eslint-enable */ + type RequestInits = | NotAny diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts index b6662952..ab972230 100644 --- a/src/internal/utils/log.ts +++ b/src/internal/utils/log.ts @@ -4,7 +4,7 @@ import { hasOwn } from './values'; import { type Writer } from '../../client'; import { RequestOptions } from '../request-options'; -type LogFn = (message: string, ...rest: unknown[]) => void; +type LogFn = (message: string, ...rest: unknown[]) => void export type Logger = { error: LogFn; warn: LogFn; @@ -21,22 +21,14 @@ const levelNumbers = { debug: 500, }; -export const parseLogLevel = ( - maybeLevel: string | undefined, - sourceName: string, - client: Writer, -): LogLevel | undefined => { +export const parseLogLevel = (maybeLevel: string | undefined, sourceName: string, client: Writer): LogLevel | undefined => { if (!maybeLevel) { return undefined; } if (hasOwn(levelNumbers, maybeLevel)) { return maybeLevel; - } - loggerFor(client).warn( - `${sourceName} was set to ${JSON.stringify(maybeLevel)}, expected one of ${JSON.stringify( - Object.keys(levelNumbers), - )}`, - ); + }; + loggerFor(client).warn(`${sourceName} was set to ${JSON.stringify(maybeLevel)}, expected one of ${JSON.stringify(Object.keys(levelNumbers))}`); return undefined; }; @@ -97,24 +89,11 @@ export const formatRequestDetails = (details: { body?: unknown; }) => { if (details.options) { - details.options = { ...details.options }; + details.options = {...details.options}; delete details.options['headers']; // redundant + leaks internals } if (details.headers) { - details.headers = Object.fromEntries( - (details.headers instanceof Headers ? [...details.headers] : Object.entries(details.headers)).map( - ([name, value]) => [ - name, - ( - name.toLowerCase() === 'authorization' || - name.toLowerCase() === 'cookie' || - name.toLowerCase() === 'set-cookie' - ) ? - '***' - : value, - ], - ), - ); + details.headers = Object.fromEntries((details.headers instanceof Headers ? [...details.headers] : Object.entries(details.headers)).map(([name, value]) => [name, name.toLowerCase() === 'authorization' || name.toLowerCase() === 'cookie' || name.toLowerCase() === 'set-cookie' ? '***' : value])) } if ('retryOfRequestLogID' in details) { if (details.retryOfRequestLogID) { @@ -122,5 +101,5 @@ export const formatRequestDetails = (details: { } delete details.retryOfRequestLogID; } - return details; -}; + return details +} diff --git a/src/internal/utils/uuid.ts b/src/internal/utils/uuid.ts index b0e53aaf..53708ba6 100644 --- a/src/internal/utils/uuid.ts +++ b/src/internal/utils/uuid.ts @@ -10,8 +10,10 @@ export let uuid4 = function () { return crypto.randomUUID(); } const u8 = new Uint8Array(1); - const randomByte = crypto ? () => crypto.getRandomValues(u8)[0]! : () => (Math.random() * 0xff) & 0xff; - return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, (c) => + const randomByte = crypto + ? () => crypto.getRandomValues(u8)[0]! + : () => (Math.random() * 0xff) & 0xff; + return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => (+c ^ (randomByte() & (15 >> (+c / 4)))).toString(16), ); -}; +} diff --git a/src/pagination.ts b/src/pagination.ts index 90bf015e..e1e5d091 100644 --- a/src/pagination.ts +++ b/src/pagination.ts @@ -1,2 +1,2 @@ /** @deprecated Import from ./core/pagination instead */ -export * from './core/pagination'; +export * from "./core/pagination" \ No newline at end of file diff --git a/src/resource.ts b/src/resource.ts index 363e3516..57a27a94 100644 --- a/src/resource.ts +++ b/src/resource.ts @@ -1,2 +1,2 @@ /** @deprecated Import from ./core/resource instead */ -export * from './core/resource'; +export * from "./core/resource" \ No newline at end of file diff --git a/src/resources/applications/applications.ts b/src/resources/applications/applications.ts index 60fa6fc8..15a52305 100644 --- a/src/resources/applications/applications.ts +++ b/src/resources/applications/applications.ts @@ -5,16 +5,7 @@ import * as ApplicationsAPI from './applications'; import * as GraphsAPI from './graphs'; import { ApplicationGraphsResponse, GraphUpdateParams, Graphs } from './graphs'; import * as JobsAPI from './jobs'; -import { - ApplicationGenerateAsyncResponse, - ApplicationGenerateAsyncResponsesApplicationJobsOffset, - ApplicationJobsListResponse, - JobCreateParams, - JobCreateResponse, - JobListParams, - JobRetryResponse, - Jobs, -} from './jobs'; +import { ApplicationGenerateAsyncResponse, ApplicationGenerateAsyncResponsesApplicationJobsOffset, ApplicationJobsListResponse, JobCreateParams, JobCreateResponse, JobListParams, JobRetryResponse, Jobs } from './jobs'; import { APIPromise } from '../../core/api-promise'; import { CursorPage, type CursorPageParams, PagePromise } from '../../core/pagination'; import { Stream } from '../../core/streaming'; @@ -37,51 +28,23 @@ export class Applications extends APIResource { * Retrieves a paginated list of no-code agents (formerly called no-code * applications) with optional filtering and sorting capabilities. */ - list( - query: ApplicationListParams | null | undefined = {}, - options?: RequestOptions, - ): PagePromise { - return this._client.getAPIList('/v1/applications', CursorPage, { - query, - ...options, - }); + list(query: ApplicationListParams | null | undefined = {}, options?: RequestOptions): PagePromise { + return this._client.getAPIList('/v1/applications', CursorPage, { query, ...options }); } /** * Generate content from an existing no-code agent (formerly called no-code * applications) with inputs. */ - generateContent( - applicationID: string, - body: ApplicationGenerateContentParamsNonStreaming, - options?: RequestOptions, - ): APIPromise; - generateContent( - applicationID: string, - body: ApplicationGenerateContentParamsStreaming, - options?: RequestOptions, - ): APIPromise>; - generateContent( - applicationID: string, - body: ApplicationGenerateContentParamsBase, - options?: RequestOptions, - ): APIPromise | ApplicationGenerateContentResponse>; - generateContent( - applicationID: string, - body: ApplicationGenerateContentParams, - options?: RequestOptions, - ): APIPromise | APIPromise> { - return this._client.post(path`/v1/applications/${applicationID}`, { - body, - ...options, - stream: body.stream ?? false, - }) as - | APIPromise - | APIPromise>; + generateContent(applicationID: string, body: ApplicationGenerateContentParamsNonStreaming, options?: RequestOptions): APIPromise + generateContent(applicationID: string, body: ApplicationGenerateContentParamsStreaming, options?: RequestOptions): APIPromise> + generateContent(applicationID: string, body: ApplicationGenerateContentParamsBase, options?: RequestOptions): APIPromise | ApplicationGenerateContentResponse> + generateContent(applicationID: string, body: ApplicationGenerateContentParams, options?: RequestOptions): APIPromise | APIPromise> { + return this._client.post(path`/v1/applications/${applicationID}`, { body, ...options, stream: body.stream ?? false }) as APIPromise | APIPromise>; } } -export type ApplicationListResponsesCursorPage = CursorPage; +export type ApplicationListResponsesCursorPage = CursorPage export interface ApplicationGenerateContentChunk { delta: ApplicationGenerateContentChunk.Delta; @@ -211,11 +174,7 @@ export namespace ApplicationRetrieveResponse { /** * Type-specific configuration options for input fields. */ - options?: - | Input.ApplicationInputDropdownOptions - | Input.ApplicationInputFileOptions - | Input.ApplicationInputMediaOptions - | Input.ApplicationInputTextOptions; + options?: Input.ApplicationInputDropdownOptions | Input.ApplicationInputFileOptions | Input.ApplicationInputMediaOptions | Input.ApplicationInputTextOptions; } export namespace Input { @@ -365,11 +324,7 @@ export namespace ApplicationListResponse { /** * Type-specific configuration options for input fields. */ - options?: - | Input.ApplicationInputDropdownOptions - | Input.ApplicationInputFileOptions - | Input.ApplicationInputMediaOptions - | Input.ApplicationInputTextOptions; + options?: Input.ApplicationInputDropdownOptions | Input.ApplicationInputFileOptions | Input.ApplicationInputMediaOptions | Input.ApplicationInputTextOptions; } export namespace Input { @@ -462,9 +417,7 @@ export interface ApplicationListParams extends CursorPageParams { type?: 'generation'; } -export type ApplicationGenerateContentParams = - | ApplicationGenerateContentParamsNonStreaming - | ApplicationGenerateContentParamsStreaming; +export type ApplicationGenerateContentParams = ApplicationGenerateContentParamsNonStreaming | ApplicationGenerateContentParamsStreaming export interface ApplicationGenerateContentParamsBase { inputs: Array; @@ -498,10 +451,8 @@ export namespace ApplicationGenerateContentParams { value: Array; } - export type ApplicationGenerateContentParamsNonStreaming = - ApplicationsAPI.ApplicationGenerateContentParamsNonStreaming; - export type ApplicationGenerateContentParamsStreaming = - ApplicationsAPI.ApplicationGenerateContentParamsStreaming; + export type ApplicationGenerateContentParamsNonStreaming = ApplicationsAPI.ApplicationGenerateContentParamsNonStreaming + export type ApplicationGenerateContentParamsStreaming = ApplicationsAPI.ApplicationGenerateContentParamsStreaming } export interface ApplicationGenerateContentParamsNonStreaming extends ApplicationGenerateContentParamsBase { @@ -533,7 +484,7 @@ export declare namespace Applications { type ApplicationListParams as ApplicationListParams, type ApplicationGenerateContentParams as ApplicationGenerateContentParams, type ApplicationGenerateContentParamsNonStreaming as ApplicationGenerateContentParamsNonStreaming, - type ApplicationGenerateContentParamsStreaming as ApplicationGenerateContentParamsStreaming, + type ApplicationGenerateContentParamsStreaming as ApplicationGenerateContentParamsStreaming }; export { @@ -544,12 +495,12 @@ export declare namespace Applications { type JobRetryResponse as JobRetryResponse, type ApplicationGenerateAsyncResponsesApplicationJobsOffset as ApplicationGenerateAsyncResponsesApplicationJobsOffset, type JobCreateParams as JobCreateParams, - type JobListParams as JobListParams, + type JobListParams as JobListParams }; export { Graphs as Graphs, type ApplicationGraphsResponse as ApplicationGraphsResponse, - type GraphUpdateParams as GraphUpdateParams, + type GraphUpdateParams as GraphUpdateParams }; } diff --git a/src/resources/applications/graphs.ts b/src/resources/applications/graphs.ts index 5a3f5b0b..4f592201 100644 --- a/src/resources/applications/graphs.ts +++ b/src/resources/applications/graphs.ts @@ -9,11 +9,7 @@ export class Graphs extends APIResource { /** * Updates the list of Knowledge Graphs associated with a no-code chat agent. */ - update( - applicationID: string, - body: GraphUpdateParams, - options?: RequestOptions, - ): APIPromise { + update(applicationID: string, body: GraphUpdateParams, options?: RequestOptions): APIPromise { return this._client.put(path`/v1/applications/${applicationID}/graphs`, { body, ...options }); } @@ -45,6 +41,6 @@ export interface GraphUpdateParams { export declare namespace Graphs { export { type ApplicationGraphsResponse as ApplicationGraphsResponse, - type GraphUpdateParams as GraphUpdateParams, + type GraphUpdateParams as GraphUpdateParams }; } diff --git a/src/resources/applications/index.ts b/src/resources/applications/index.ts index da90190f..9684db79 100644 --- a/src/resources/applications/index.ts +++ b/src/resources/applications/index.ts @@ -1,25 +1,5 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -export { - Applications, - type ApplicationGenerateContentChunk, - type ApplicationGenerateContentResponse, - type ApplicationRetrieveResponse, - type ApplicationListResponse, - type ApplicationListParams, - type ApplicationGenerateContentParams, - type ApplicationGenerateContentParamsNonStreaming, - type ApplicationGenerateContentParamsStreaming, - type ApplicationListResponsesCursorPage, -} from './applications'; -export { Graphs, type ApplicationGraphsResponse, type GraphUpdateParams } from './graphs'; -export { - Jobs, - type ApplicationGenerateAsyncResponse, - type ApplicationJobsListResponse, - type JobCreateResponse, - type JobRetryResponse, - type JobCreateParams, - type JobListParams, - type ApplicationGenerateAsyncResponsesApplicationJobsOffset, -} from './jobs'; +export { Applications, type ApplicationGenerateContentChunk, type ApplicationGenerateContentResponse, type ApplicationRetrieveResponse, type ApplicationListResponse, type ApplicationListParams, type ApplicationGenerateContentParams, type ApplicationGenerateContentParamsNonStreaming, type ApplicationGenerateContentParamsStreaming, type ApplicationListResponsesCursorPage } from './applications';; +export { Graphs, type ApplicationGraphsResponse, type GraphUpdateParams } from './graphs';; +export { Jobs, type ApplicationGenerateAsyncResponse, type ApplicationJobsListResponse, type JobCreateResponse, type JobRetryResponse, type JobCreateParams, type JobListParams, type ApplicationGenerateAsyncResponsesApplicationJobsOffset } from './jobs';; diff --git a/src/resources/applications/jobs.ts b/src/resources/applications/jobs.ts index 20fb29aa..80667e69 100644 --- a/src/resources/applications/jobs.ts +++ b/src/resources/applications/jobs.ts @@ -12,11 +12,7 @@ export class Jobs extends APIResource { * Generate content asynchronously from an existing no-code agent (formerly called * no-code applications) with inputs. */ - create( - applicationID: string, - body: JobCreateParams, - options?: RequestOptions, - ): APIPromise { + create(applicationID: string, body: JobCreateParams, options?: RequestOptions): APIPromise { return this._client.post(path`/v1/applications/${applicationID}/jobs`, { body, ...options }); } @@ -31,16 +27,8 @@ export class Jobs extends APIResource { * Retrieve all jobs created via the async API, linked to the provided application * ID (or alias). */ - list( - applicationID: string, - query: JobListParams | null | undefined = {}, - options?: RequestOptions, - ): PagePromise { - return this._client.getAPIList( - path`/v1/applications/${applicationID}/jobs`, - ApplicationJobsOffset, - { query, ...options }, - ); + list(applicationID: string, query: JobListParams | null | undefined = {}, options?: RequestOptions): PagePromise { + return this._client.getAPIList(path`/v1/applications/${applicationID}/jobs`, ApplicationJobsOffset, { query, ...options }); } /** @@ -52,8 +40,7 @@ export class Jobs extends APIResource { } } -export type ApplicationGenerateAsyncResponsesApplicationJobsOffset = - ApplicationJobsOffset; +export type ApplicationGenerateAsyncResponsesApplicationJobsOffset = ApplicationJobsOffset export interface ApplicationGenerateAsyncResponse { /** @@ -201,6 +188,6 @@ export declare namespace Jobs { type JobRetryResponse as JobRetryResponse, type ApplicationGenerateAsyncResponsesApplicationJobsOffset as ApplicationGenerateAsyncResponsesApplicationJobsOffset, type JobCreateParams as JobCreateParams, - type JobListParams as JobListParams, + type JobListParams as JobListParams }; } diff --git a/src/resources/chat.ts b/src/resources/chat.ts index ec2a4da6..be9a8d6b 100644 --- a/src/resources/chat.ts +++ b/src/resources/chat.ts @@ -17,19 +17,11 @@ export class Chat extends APIResource { * below is for non-streaming. To learn about streaming responses, see the * [chat completion guide](https://dev.writer.com/home/chat-completion). */ - chat(body: ChatChatParamsNonStreaming, options?: RequestOptions): APIPromise; - chat(body: ChatChatParamsStreaming, options?: RequestOptions): APIPromise>; - chat( - body: ChatChatParamsBase, - options?: RequestOptions, - ): APIPromise | ChatCompletion>; - chat( - body: ChatChatParams, - options?: RequestOptions, - ): APIPromise | APIPromise> { - return this._client.post('/v1/chat', { body, ...options, stream: body.stream ?? false }) as - | APIPromise - | APIPromise>; + chat(body: ChatChatParamsNonStreaming, options?: RequestOptions): APIPromise + chat(body: ChatChatParamsStreaming, options?: RequestOptions): APIPromise> + chat(body: ChatChatParamsBase, options?: RequestOptions): APIPromise | ChatCompletion> + chat(body: ChatChatParams, options?: RequestOptions): APIPromise | APIPromise> { + return this._client.post('/v1/chat', { body, ...options, stream: body.stream ?? false }) as APIPromise | APIPromise>; } /** @@ -618,7 +610,7 @@ export namespace ChatCompletionUsage { } } -export type ChatChatParams = ChatChatParamsNonStreaming | ChatChatParamsStreaming; +export type ChatChatParams = ChatChatParamsNonStreaming | ChatChatParamsStreaming export interface ChatChatParamsBase { /** @@ -833,8 +825,8 @@ export namespace ChatChatParams { include_usage: boolean; } - export type ChatChatParamsNonStreaming = ChatAPI.ChatChatParamsNonStreaming; - export type ChatChatParamsStreaming = ChatAPI.ChatChatParamsStreaming; + export type ChatChatParamsNonStreaming = ChatAPI.ChatChatParamsNonStreaming + export type ChatChatParamsStreaming = ChatAPI.ChatChatParamsStreaming } export interface ChatChatParamsNonStreaming extends ChatChatParamsBase { diff --git a/src/resources/completions.ts b/src/resources/completions.ts index 3733da13..22236809 100644 --- a/src/resources/completions.ts +++ b/src/resources/completions.ts @@ -20,22 +20,11 @@ export class Completions extends APIResource { * }); * ``` */ - create(body: CompletionCreateParamsNonStreaming, options?: RequestOptions): APIPromise; - create( - body: CompletionCreateParamsStreaming, - options?: RequestOptions, - ): APIPromise>; - create( - body: CompletionCreateParamsBase, - options?: RequestOptions, - ): APIPromise | Completion>; - create( - body: CompletionCreateParams, - options?: RequestOptions, - ): APIPromise | APIPromise> { - return this._client.post('/v1/completions', { body, ...options, stream: body.stream ?? false }) as - | APIPromise - | APIPromise>; + create(body: CompletionCreateParamsNonStreaming, options?: RequestOptions): APIPromise + create(body: CompletionCreateParamsStreaming, options?: RequestOptions): APIPromise> + create(body: CompletionCreateParamsBase, options?: RequestOptions): APIPromise | Completion> + create(body: CompletionCreateParams, options?: RequestOptions): APIPromise | APIPromise> { + return this._client.post('/v1/completions', { body, ...options, stream: body.stream ?? false }) as APIPromise | APIPromise>; } } @@ -127,7 +116,7 @@ export interface CompletionParams { top_p?: number; } -export type CompletionCreateParams = CompletionCreateParamsNonStreaming | CompletionCreateParamsStreaming; +export type CompletionCreateParams = CompletionCreateParamsNonStreaming | CompletionCreateParamsStreaming export interface CompletionCreateParamsBase { /** @@ -188,8 +177,8 @@ export interface CompletionCreateParamsBase { } export namespace CompletionCreateParams { - export type CompletionCreateParamsNonStreaming = CompletionsAPI.CompletionCreateParamsNonStreaming; - export type CompletionCreateParamsStreaming = CompletionsAPI.CompletionCreateParamsStreaming; + export type CompletionCreateParamsNonStreaming = CompletionsAPI.CompletionCreateParamsNonStreaming + export type CompletionCreateParamsStreaming = CompletionsAPI.CompletionCreateParamsStreaming } export interface CompletionCreateParamsNonStreaming extends CompletionCreateParamsBase { @@ -217,6 +206,6 @@ export declare namespace Completions { type CompletionParams as CompletionParams, type CompletionCreateParams as CompletionCreateParams, type CompletionCreateParamsNonStreaming as CompletionCreateParamsNonStreaming, - type CompletionCreateParamsStreaming as CompletionCreateParamsStreaming, + type CompletionCreateParamsStreaming as CompletionCreateParamsStreaming }; } diff --git a/src/resources/files.ts b/src/resources/files.ts index 4c2a2690..514dcda6 100644 --- a/src/resources/files.ts +++ b/src/resources/files.ts @@ -4,6 +4,7 @@ import { APIResource } from '../core/resource'; import { APIPromise } from '../core/api-promise'; import { CursorPage, type CursorPageParams, PagePromise } from '../core/pagination'; import { type Uploadable } from '../core/uploads'; +import type { Response } from '../internal/builtin-types'; import { buildHeaders } from '../internal/headers'; import { RequestOptions } from '../internal/request-options'; import { path } from '../internal/utils/path'; @@ -21,10 +22,7 @@ export class Files extends APIResource { * Retrieve a paginated list of files with optional filtering by status, graph * association, and file type. */ - list( - query: FileListParams | null | undefined = {}, - options?: RequestOptions, - ): PagePromise { + list(query: FileListParams | null | undefined = {}, options?: RequestOptions): PagePromise { return this._client.getAPIList('/v1/files', CursorPage, { query, ...options }); } @@ -40,11 +38,7 @@ export class Files extends APIResource { * in the appropriate MIME type. */ download(fileID: string, options?: RequestOptions): APIPromise { - return this._client.get(path`/v1/files/${fileID}/download`, { - ...options, - headers: buildHeaders([{ Accept: 'application/octet-stream' }, options?.headers]), - __binaryResponse: true, - }); + return this._client.get(path`/v1/files/${fileID}/download`, { ...options, headers: buildHeaders([{Accept: 'application/octet-stream'}, options?.headers]), __binaryResponse: true }); } /** @@ -79,7 +73,7 @@ export class Files extends APIResource { } } -export type FilesCursorPage = CursorPage; +export type FilesCursorPage = CursorPage export interface File { /** @@ -207,6 +201,6 @@ export declare namespace Files { type FilesCursorPage as FilesCursorPage, type FileListParams as FileListParams, type FileRetryParams as FileRetryParams, - type FileUploadParams as FileUploadParams, + type FileUploadParams as FileUploadParams }; } diff --git a/src/resources/graphs.ts b/src/resources/graphs.ts index a7f13b96..06b4612e 100644 --- a/src/resources/graphs.ts +++ b/src/resources/graphs.ts @@ -28,21 +28,14 @@ export class Graphs extends APIResource { /** * Update the name and description of a Knowledge Graph. */ - update( - graphID: string, - body: GraphUpdateParams, - options?: RequestOptions, - ): APIPromise { + update(graphID: string, body: GraphUpdateParams, options?: RequestOptions): APIPromise { return this._client.put(path`/v1/graphs/${graphID}`, { body, ...options }); } /** * Retrieve a list of Knowledge Graphs. */ - list( - query: GraphListParams | null | undefined = {}, - options?: RequestOptions, - ): PagePromise { + list(query: GraphListParams | null | undefined = {}, options?: RequestOptions): PagePromise { return this._client.getAPIList('/v1/graphs', CursorPage, { query, ...options }); } @@ -56,49 +49,30 @@ export class Graphs extends APIResource { /** * Add a file to a Knowledge Graph. */ - addFileToGraph( - graphID: string, - body: GraphAddFileToGraphParams, - options?: RequestOptions, - ): APIPromise { + addFileToGraph(graphID: string, body: GraphAddFileToGraphParams, options?: RequestOptions): APIPromise { return this._client.post(path`/v1/graphs/${graphID}/file`, { body, ...options }); } /** * Ask a question to specified Knowledge Graphs. */ - question(body: GraphQuestionParamsNonStreaming, options?: RequestOptions): APIPromise; - question( - body: GraphQuestionParamsStreaming, - options?: RequestOptions, - ): APIPromise>; - question( - body: GraphQuestionParamsBase, - options?: RequestOptions, - ): APIPromise | Question>; - question( - body: GraphQuestionParams, - options?: RequestOptions, - ): APIPromise | APIPromise> { - return this._client.post('/v1/graphs/question', { body, ...options, stream: body.stream ?? false }) as - | APIPromise - | APIPromise>; + question(body: GraphQuestionParamsNonStreaming, options?: RequestOptions): APIPromise + question(body: GraphQuestionParamsStreaming, options?: RequestOptions): APIPromise> + question(body: GraphQuestionParamsBase, options?: RequestOptions): APIPromise | Question> + question(body: GraphQuestionParams, options?: RequestOptions): APIPromise | APIPromise> { + return this._client.post('/v1/graphs/question', { body, ...options, stream: body.stream ?? false }) as APIPromise | APIPromise>; } /** * Remove a file from a Knowledge Graph. */ - removeFileFromGraph( - fileID: string, - params: GraphRemoveFileFromGraphParams, - options?: RequestOptions, - ): APIPromise { - const { graph_id } = params; + removeFileFromGraph(fileID: string, params: GraphRemoveFileFromGraphParams, options?: RequestOptions): APIPromise { + const { graph_id } = params return this._client.delete(path`/v1/graphs/${graph_id}/file/${fileID}`, options); } } -export type GraphsCursorPage = CursorPage; +export type GraphsCursorPage = CursorPage export interface Graph { /** @@ -203,12 +177,7 @@ export namespace Graph { /** * The type of error that occurred during processing, if any. */ - error_type?: - | 'invalid_url' - | 'not_searchable' - | 'not_found' - | 'paywall_or_login_page' - | 'unexpected_error'; + error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; } } } @@ -405,12 +374,7 @@ export namespace GraphCreateResponse { /** * The type of error that occurred during processing, if any. */ - error_type?: - | 'invalid_url' - | 'not_searchable' - | 'not_found' - | 'paywall_or_login_page' - | 'unexpected_error'; + error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; } } } @@ -478,12 +442,7 @@ export namespace GraphUpdateResponse { /** * The type of error that occurred during processing, if any. */ - error_type?: - | 'invalid_url' - | 'not_searchable' - | 'not_found' - | 'paywall_or_login_page' - | 'unexpected_error'; + error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; } } } @@ -587,7 +546,7 @@ export interface GraphAddFileToGraphParams { file_id: string; } -export type GraphQuestionParams = GraphQuestionParamsNonStreaming | GraphQuestionParamsStreaming; +export type GraphQuestionParams = GraphQuestionParamsNonStreaming | GraphQuestionParamsStreaming export interface GraphQuestionParamsBase { /** @@ -690,8 +649,8 @@ export namespace GraphQuestionParams { semantic_threshold?: number; } - export type GraphQuestionParamsNonStreaming = GraphsAPI.GraphQuestionParamsNonStreaming; - export type GraphQuestionParamsStreaming = GraphsAPI.GraphQuestionParamsStreaming; + export type GraphQuestionParamsNonStreaming = GraphsAPI.GraphQuestionParamsNonStreaming + export type GraphQuestionParamsStreaming = GraphsAPI.GraphQuestionParamsStreaming } export interface GraphQuestionParamsNonStreaming extends GraphQuestionParamsBase { @@ -736,6 +695,6 @@ export declare namespace Graphs { type GraphQuestionParams as GraphQuestionParams, type GraphQuestionParamsNonStreaming as GraphQuestionParamsNonStreaming, type GraphQuestionParamsStreaming as GraphQuestionParamsStreaming, - type GraphRemoveFileFromGraphParams as GraphRemoveFileFromGraphParams, + type GraphRemoveFileFromGraphParams as GraphRemoveFileFromGraphParams }; } diff --git a/src/resources/index.ts b/src/resources/index.ts index 528a38ec..6fb12517 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -1,80 +1,12 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -export * from './shared'; -export { - Applications, - type ApplicationGenerateContentChunk, - type ApplicationGenerateContentResponse, - type ApplicationRetrieveResponse, - type ApplicationListResponse, - type ApplicationListParams, - type ApplicationGenerateContentParams, - type ApplicationGenerateContentParamsNonStreaming, - type ApplicationGenerateContentParamsStreaming, - type ApplicationListResponsesCursorPage, -} from './applications/applications'; -export { - Chat, - type ChatCompletion, - type ChatCompletionChoice, - type ChatCompletionChunk, - type ChatCompletionMessage, - type ChatCompletionParams, - type ChatCompletionUsage, - type ChatChatParams, - type ChatChatParamsNonStreaming, - type ChatChatParamsStreaming, -} from './chat'; -export { - Completions, - type Completion, - type CompletionChunk, - type CompletionParams, - type CompletionCreateParams, - type CompletionCreateParamsNonStreaming, - type CompletionCreateParamsStreaming, -} from './completions'; -export { - Files, - type File, - type FileDeleteResponse, - type FileRetryResponse, - type FileListParams, - type FileRetryParams, - type FileUploadParams, - type FilesCursorPage, -} from './files'; -export { - Graphs, - type Graph, - type Question, - type QuestionResponseChunk, - type GraphCreateResponse, - type GraphUpdateResponse, - type GraphDeleteResponse, - type GraphRemoveFileFromGraphResponse, - type GraphCreateParams, - type GraphUpdateParams, - type GraphListParams, - type GraphAddFileToGraphParams, - type GraphQuestionParams, - type GraphQuestionParamsNonStreaming, - type GraphQuestionParamsStreaming, - type GraphRemoveFileFromGraphParams, - type GraphsCursorPage, -} from './graphs'; -export { Models, type ModelListResponse } from './models'; -export { - Tools, - type ToolParsePdfResponse, - type ToolWebSearchResponse, - type ToolParsePdfParams, - type ToolWebSearchParams, -} from './tools'; -export { - Translation, - type TranslationRequest, - type TranslationResponse, - type TranslationTranslateParams, -} from './translation'; -export { Vision, type VisionRequest, type VisionResponse, type VisionAnalyzeParams } from './vision'; +export * from './shared';; +export { Applications, type ApplicationGenerateContentChunk, type ApplicationGenerateContentResponse, type ApplicationRetrieveResponse, type ApplicationListResponse, type ApplicationListParams, type ApplicationGenerateContentParams, type ApplicationGenerateContentParamsNonStreaming, type ApplicationGenerateContentParamsStreaming, type ApplicationListResponsesCursorPage } from './applications/applications';; +export { Chat, type ChatCompletion, type ChatCompletionChoice, type ChatCompletionChunk, type ChatCompletionMessage, type ChatCompletionParams, type ChatCompletionUsage, type ChatChatParams, type ChatChatParamsNonStreaming, type ChatChatParamsStreaming } from './chat';; +export { Completions, type Completion, type CompletionChunk, type CompletionParams, type CompletionCreateParams, type CompletionCreateParamsNonStreaming, type CompletionCreateParamsStreaming } from './completions';; +export { Files, type File, type FileDeleteResponse, type FileRetryResponse, type FileListParams, type FileRetryParams, type FileUploadParams, type FilesCursorPage } from './files';; +export { Graphs, type Graph, type Question, type QuestionResponseChunk, type GraphCreateResponse, type GraphUpdateResponse, type GraphDeleteResponse, type GraphRemoveFileFromGraphResponse, type GraphCreateParams, type GraphUpdateParams, type GraphListParams, type GraphAddFileToGraphParams, type GraphQuestionParams, type GraphQuestionParamsNonStreaming, type GraphQuestionParamsStreaming, type GraphRemoveFileFromGraphParams, type GraphsCursorPage } from './graphs';; +export { Models, type ModelListResponse } from './models';; +export { Tools, type ToolParsePdfResponse, type ToolWebSearchResponse, type ToolParsePdfParams, type ToolWebSearchParams } from './tools';; +export { Translation, type TranslationRequest, type TranslationResponse, type TranslationTranslateParams } from './translation';; +export { Vision, type VisionRequest, type VisionResponse, type VisionAnalyzeParams } from './vision';; diff --git a/src/resources/models.ts b/src/resources/models.ts index f19b98e9..1214b16f 100644 --- a/src/resources/models.ts +++ b/src/resources/models.ts @@ -42,5 +42,7 @@ export namespace ModelListResponse { } export declare namespace Models { - export { type ModelListResponse as ModelListResponse }; + export { + type ModelListResponse as ModelListResponse + }; } diff --git a/src/resources/shared.ts b/src/resources/shared.ts index c852af4e..dd8b64ff 100644 --- a/src/resources/shared.ts +++ b/src/resources/shared.ts @@ -39,7 +39,7 @@ export interface FunctionDefinition { /** * The parameters of the function. */ -export type FunctionParams = { [key: string]: unknown }; +export type FunctionParams = { [key: string]: unknown } export interface GraphData { /** @@ -256,13 +256,7 @@ export interface ToolChoiceString { * A tool that uses Palmyra Translate to translate text. Note that this tool does * not stream results. The response is returned after the translation is complete. */ -export type ToolParam = - | ToolParam.FunctionTool - | ToolParam.GraphTool - | ToolParam.LlmTool - | ToolParam.TranslationTool - | ToolParam.VisionTool - | ToolParam.WebSearchTool; +export type ToolParam = ToolParam.FunctionTool | ToolParam.GraphTool | ToolParam.LlmTool | ToolParam.TranslationTool | ToolParam.VisionTool | ToolParam.WebSearchTool export namespace ToolParam { export interface FunctionTool { diff --git a/src/resources/tools.ts b/src/resources/tools.ts index b6bf9568..838b5965 100644 --- a/src/resources/tools.ts +++ b/src/resources/tools.ts @@ -11,11 +11,7 @@ export class Tools extends APIResource { * * @deprecated Will be removed in a future release. A replacement PDF parsing tool for chat completions is planned; see documentation at dev.writer.com for more information. */ - parsePdf( - fileID: string, - body: ToolParsePdfParams, - options?: RequestOptions, - ): APIPromise { + parsePdf(fileID: string, body: ToolParsePdfParams, options?: RequestOptions): APIPromise { return this._client.post(path`/v1/tools/pdf-parser/${fileID}`, { body, ...options }); } @@ -88,173 +84,7 @@ export interface ToolWebSearchParams { * Localizes search results to a specific country. Only applies to general topic * searches. */ - country?: - | 'afghanistan' - | 'albania' - | 'algeria' - | 'andorra' - | 'angola' - | 'argentina' - | 'armenia' - | 'australia' - | 'austria' - | 'azerbaijan' - | 'bahamas' - | 'bahrain' - | 'bangladesh' - | 'barbados' - | 'belarus' - | 'belgium' - | 'belize' - | 'benin' - | 'bhutan' - | 'bolivia' - | 'bosnia and herzegovina' - | 'botswana' - | 'brazil' - | 'brunei' - | 'bulgaria' - | 'burkina faso' - | 'burundi' - | 'cambodia' - | 'cameroon' - | 'canada' - | 'cape verde' - | 'central african republic' - | 'chad' - | 'chile' - | 'china' - | 'colombia' - | 'comoros' - | 'congo' - | 'costa rica' - | 'croatia' - | 'cuba' - | 'cyprus' - | 'czech republic' - | 'denmark' - | 'djibouti' - | 'dominican republic' - | 'ecuador' - | 'egypt' - | 'el salvador' - | 'equatorial guinea' - | 'eritrea' - | 'estonia' - | 'ethiopia' - | 'fiji' - | 'finland' - | 'france' - | 'gabon' - | 'gambia' - | 'georgia' - | 'germany' - | 'ghana' - | 'greece' - | 'guatemala' - | 'guinea' - | 'haiti' - | 'honduras' - | 'hungary' - | 'iceland' - | 'india' - | 'indonesia' - | 'iran' - | 'iraq' - | 'ireland' - | 'israel' - | 'italy' - | 'jamaica' - | 'japan' - | 'jordan' - | 'kazakhstan' - | 'kenya' - | 'kuwait' - | 'kyrgyzstan' - | 'latvia' - | 'lebanon' - | 'lesotho' - | 'liberia' - | 'libya' - | 'liechtenstein' - | 'lithuania' - | 'luxembourg' - | 'madagascar' - | 'malawi' - | 'malaysia' - | 'maldives' - | 'mali' - | 'malta' - | 'mauritania' - | 'mauritius' - | 'mexico' - | 'moldova' - | 'monaco' - | 'mongolia' - | 'montenegro' - | 'morocco' - | 'mozambique' - | 'myanmar' - | 'namibia' - | 'nepal' - | 'netherlands' - | 'new zealand' - | 'nicaragua' - | 'niger' - | 'nigeria' - | 'north korea' - | 'north macedonia' - | 'norway' - | 'oman' - | 'pakistan' - | 'panama' - | 'papua new guinea' - | 'paraguay' - | 'peru' - | 'philippines' - | 'poland' - | 'portugal' - | 'qatar' - | 'romania' - | 'russia' - | 'rwanda' - | 'saudi arabia' - | 'senegal' - | 'serbia' - | 'singapore' - | 'slovakia' - | 'slovenia' - | 'somalia' - | 'south africa' - | 'south korea' - | 'south sudan' - | 'spain' - | 'sri lanka' - | 'sudan' - | 'sweden' - | 'switzerland' - | 'syria' - | 'taiwan' - | 'tajikistan' - | 'tanzania' - | 'thailand' - | 'togo' - | 'trinidad and tobago' - | 'tunisia' - | 'turkey' - | 'turkmenistan' - | 'uganda' - | 'ukraine' - | 'united arab emirates' - | 'united kingdom' - | 'united states' - | 'uruguay' - | 'uzbekistan' - | 'venezuela' - | 'vietnam' - | 'yemen' - | 'zambia' - | 'zimbabwe'; + country?: 'afghanistan' | 'albania' | 'algeria' | 'andorra' | 'angola' | 'argentina' | 'armenia' | 'australia' | 'austria' | 'azerbaijan' | 'bahamas' | 'bahrain' | 'bangladesh' | 'barbados' | 'belarus' | 'belgium' | 'belize' | 'benin' | 'bhutan' | 'bolivia' | 'bosnia and herzegovina' | 'botswana' | 'brazil' | 'brunei' | 'bulgaria' | 'burkina faso' | 'burundi' | 'cambodia' | 'cameroon' | 'canada' | 'cape verde' | 'central african republic' | 'chad' | 'chile' | 'china' | 'colombia' | 'comoros' | 'congo' | 'costa rica' | 'croatia' | 'cuba' | 'cyprus' | 'czech republic' | 'denmark' | 'djibouti' | 'dominican republic' | 'ecuador' | 'egypt' | 'el salvador' | 'equatorial guinea' | 'eritrea' | 'estonia' | 'ethiopia' | 'fiji' | 'finland' | 'france' | 'gabon' | 'gambia' | 'georgia' | 'germany' | 'ghana' | 'greece' | 'guatemala' | 'guinea' | 'haiti' | 'honduras' | 'hungary' | 'iceland' | 'india' | 'indonesia' | 'iran' | 'iraq' | 'ireland' | 'israel' | 'italy' | 'jamaica' | 'japan' | 'jordan' | 'kazakhstan' | 'kenya' | 'kuwait' | 'kyrgyzstan' | 'latvia' | 'lebanon' | 'lesotho' | 'liberia' | 'libya' | 'liechtenstein' | 'lithuania' | 'luxembourg' | 'madagascar' | 'malawi' | 'malaysia' | 'maldives' | 'mali' | 'malta' | 'mauritania' | 'mauritius' | 'mexico' | 'moldova' | 'monaco' | 'mongolia' | 'montenegro' | 'morocco' | 'mozambique' | 'myanmar' | 'namibia' | 'nepal' | 'netherlands' | 'new zealand' | 'nicaragua' | 'niger' | 'nigeria' | 'north korea' | 'north macedonia' | 'norway' | 'oman' | 'pakistan' | 'panama' | 'papua new guinea' | 'paraguay' | 'peru' | 'philippines' | 'poland' | 'portugal' | 'qatar' | 'romania' | 'russia' | 'rwanda' | 'saudi arabia' | 'senegal' | 'serbia' | 'singapore' | 'slovakia' | 'slovenia' | 'somalia' | 'south africa' | 'south korea' | 'south sudan' | 'spain' | 'sri lanka' | 'sudan' | 'sweden' | 'switzerland' | 'syria' | 'taiwan' | 'tajikistan' | 'tanzania' | 'thailand' | 'togo' | 'trinidad and tobago' | 'tunisia' | 'turkey' | 'turkmenistan' | 'uganda' | 'ukraine' | 'united arab emirates' | 'united kingdom' | 'united states' | 'uruguay' | 'uzbekistan' | 'venezuela' | 'vietnam' | 'yemen' | 'zambia' | 'zimbabwe'; /** * For news topic searches, specifies how many days of news coverage to include. @@ -330,6 +160,6 @@ export declare namespace Tools { type ToolParsePdfResponse as ToolParsePdfResponse, type ToolWebSearchResponse as ToolWebSearchResponse, type ToolParsePdfParams as ToolParsePdfParams, - type ToolWebSearchParams as ToolWebSearchParams, + type ToolWebSearchParams as ToolWebSearchParams }; } diff --git a/src/resources/translation.ts b/src/resources/translation.ts index b5ce8c32..cf345045 100644 --- a/src/resources/translation.ts +++ b/src/resources/translation.ts @@ -136,6 +136,6 @@ export declare namespace Translation { export { type TranslationRequest as TranslationRequest, type TranslationResponse as TranslationResponse, - type TranslationTranslateParams as TranslationTranslateParams, + type TranslationTranslateParams as TranslationTranslateParams }; } diff --git a/src/resources/vision.ts b/src/resources/vision.ts index 87544c76..b3ec114a 100644 --- a/src/resources/vision.ts +++ b/src/resources/vision.ts @@ -124,6 +124,6 @@ export declare namespace Vision { export { type VisionRequest as VisionRequest, type VisionResponse as VisionResponse, - type VisionAnalyzeParams as VisionAnalyzeParams, + type VisionAnalyzeParams as VisionAnalyzeParams }; } diff --git a/src/streaming.ts b/src/streaming.ts index 9e6da106..17085360 100644 --- a/src/streaming.ts +++ b/src/streaming.ts @@ -1,2 +1,2 @@ /** @deprecated Import from ./core/streaming instead */ -export * from './core/streaming'; +export * from "./core/streaming" \ No newline at end of file diff --git a/src/uploads.ts b/src/uploads.ts index b2ef6471..d5437085 100644 --- a/src/uploads.ts +++ b/src/uploads.ts @@ -1,2 +1,2 @@ /** @deprecated Import from ./core/uploads instead */ -export * from './core/uploads'; +export * from "./core/uploads" \ No newline at end of file diff --git a/src/version.ts b/src/version.ts index 1e17ebcc..c2755d49 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '3.0.0-rc.1'; // x-release-please-version +export const VERSION = '3.0.0-rc.1';// x-release-please-version diff --git a/tests/api-resources/applications/applications.test.ts b/tests/api-resources/applications/applications.test.ts index a3177bac..5211d079 100644 --- a/tests/api-resources/applications/applications.test.ts +++ b/tests/api-resources/applications/applications.test.ts @@ -2,10 +2,7 @@ import Writer from 'writer-sdk'; -const client = new Writer({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); +const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); describe('resource applications', () => { test('retrieve', async () => { @@ -32,24 +29,19 @@ describe('resource applications', () => { test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.applications.list( - { - after: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - before: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - limit: 0, - order: 'asc', - type: 'generation', - }, - { path: '/_stainless_unknown_path' }, - ), - ).rejects.toThrow(Writer.NotFoundError); + await expect(client.applications.list({ + after: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + before: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + limit: 0, + order: 'asc', + type: 'generation', + }, { path: '/_stainless_unknown_path' })) + .rejects + .toThrow(Writer.NotFoundError); }); test('generateContent: only required params', async () => { - const responsePromise = client.applications.generateContent('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { - inputs: [{ id: 'id', value: ['string'] }], - }); + const responsePromise = client.applications.generateContent('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { inputs: [{ id: 'id', value: ['string'] }] }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -60,9 +52,6 @@ describe('resource applications', () => { }); test('generateContent: required and optional params', async () => { - const response = await client.applications.generateContent('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { - inputs: [{ id: 'id', value: ['string'] }], - stream: false, - }); + const response = await client.applications.generateContent('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { inputs: [{ id: 'id', value: ['string'] }], stream: false }); }); }); diff --git a/tests/api-resources/applications/graphs.test.ts b/tests/api-resources/applications/graphs.test.ts index 6edb71c0..f97a392d 100644 --- a/tests/api-resources/applications/graphs.test.ts +++ b/tests/api-resources/applications/graphs.test.ts @@ -2,16 +2,11 @@ import Writer from 'writer-sdk'; -const client = new Writer({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); +const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); describe('resource graphs', () => { test('update: only required params', async () => { - const responsePromise = client.applications.graphs.update('application_id', { - graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], - }); + const responsePromise = client.applications.graphs.update('application_id', { graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -22,9 +17,7 @@ describe('resource graphs', () => { }); test('update: required and optional params', async () => { - const response = await client.applications.graphs.update('application_id', { - graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], - }); + const response = await client.applications.graphs.update('application_id', { graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] }); }); test('list', async () => { diff --git a/tests/api-resources/applications/jobs.test.ts b/tests/api-resources/applications/jobs.test.ts index 1b53c41e..0a270645 100644 --- a/tests/api-resources/applications/jobs.test.ts +++ b/tests/api-resources/applications/jobs.test.ts @@ -2,16 +2,11 @@ import Writer from 'writer-sdk'; -const client = new Writer({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); +const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); describe('resource jobs', () => { test('create: only required params', async () => { - const responsePromise = client.applications.jobs.create('application_id', { - inputs: [{ id: 'id', value: ['string'] }], - }); + const responsePromise = client.applications.jobs.create('application_id', { inputs: [{ id: 'id', value: ['string'] }] }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -22,9 +17,7 @@ describe('resource jobs', () => { }); test('create: required and optional params', async () => { - const response = await client.applications.jobs.create('application_id', { - inputs: [{ id: 'id', value: ['string'] }], - }); + const response = await client.applications.jobs.create('application_id', { inputs: [{ id: 'id', value: ['string'] }] }); }); test('retrieve', async () => { @@ -51,17 +44,13 @@ describe('resource jobs', () => { test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.applications.jobs.list( - 'application_id', - { - limit: 0, - offset: 0, - status: 'in_progress', - }, - { path: '/_stainless_unknown_path' }, - ), - ).rejects.toThrow(Writer.NotFoundError); + await expect(client.applications.jobs.list('application_id', { + limit: 0, + offset: 0, + status: 'in_progress', + }, { path: '/_stainless_unknown_path' })) + .rejects + .toThrow(Writer.NotFoundError); }); test('retry', async () => { diff --git a/tests/api-resources/chat.test.ts b/tests/api-resources/chat.test.ts index 5094a0d3..9778f8d9 100644 --- a/tests/api-resources/chat.test.ts +++ b/tests/api-resources/chat.test.ts @@ -2,10 +2,7 @@ import Writer from 'writer-sdk'; -const client = new Writer({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); +const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); describe('resource chat', () => { test('chat: only required params', async () => { @@ -21,77 +18,62 @@ describe('resource chat', () => { test('chat: required and optional params', async () => { const response = await client.chat.chat({ - messages: [ - { - role: 'user', - content: 'string', - graph_data: { - references: { - files: [ - { - fileId: 'fileId', - score: 0, - text: 'text', - cite: 'cite', - page: 0, - }, - ], - web: [ - { - score: 0, - text: 'text', - title: 'title', - url: 'https://example.com', - }, - ], - }, - sources: [{ file_id: 'file_id', snippet: 'snippet' }], - status: 'processing', - subqueries: [ - { - answer: 'answer', - query: 'query', - sources: [{ file_id: 'file_id', snippet: 'snippet' }], - }, - ], - }, - name: 'name', - refusal: 'refusal', - tool_call_id: 'tool_call_id', - tool_calls: [ - { - id: 'id', - function: { arguments: 'arguments', name: 'name' }, - type: 'function', - index: 0, - }, - ], - }, - ], - model: 'model', - logprobs: true, - max_tokens: 0, - n: 0, - response_format: { - type: 'text', - json_schema: {}, - }, - stop: ['string'], - stream: false, - stream_options: { include_usage: true }, - temperature: 0, - tool_choice: { value: 'none' }, - tools: [ - { - function: { - name: 'name', - description: 'description', - parameters: { foo: 'bar' }, - }, - type: 'function', - }, - ], - top_p: 0, - }); + messages: [{ + role: 'user', + content: 'string', + graph_data: { + references: { files: [{ + fileId: 'fileId', + score: 0, + text: 'text', + cite: 'cite', + page: 0, + }], web: [{ + score: 0, + text: 'text', + title: 'title', + url: 'https://example.com', + }] }, + sources: [{ file_id: 'file_id', snippet: 'snippet' }], + status: 'processing', + subqueries: [{ + answer: 'answer', + query: 'query', + sources: [{ file_id: 'file_id', snippet: 'snippet' }], + }], + }, + name: 'name', + refusal: 'refusal', + tool_call_id: 'tool_call_id', + tool_calls: [{ + id: 'id', + function: { arguments: 'arguments', name: 'name' }, + type: 'function', + index: 0, + }], + }], + model: 'model', + logprobs: true, + max_tokens: 0, + n: 0, + response_format: { + type: 'text', + json_schema: {}, + }, + stop: ['string'], + stream: false, + stream_options: { include_usage: true }, + temperature: 0, + tool_choice: { value: 'none' }, + tools: [{ + function: { + name: 'name', + description: 'description', + parameters: { foo: 'bar' }, + }, + type: 'function', + }], + top_p: 0, + }); }); }); diff --git a/tests/api-resources/completions.test.ts b/tests/api-resources/completions.test.ts index bdc1f37b..e21af584 100644 --- a/tests/api-resources/completions.test.ts +++ b/tests/api-resources/completions.test.ts @@ -2,17 +2,11 @@ import Writer from 'writer-sdk'; -const client = new Writer({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); +const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); describe('resource completions', () => { test('create: only required params', async () => { - const responsePromise = client.completions.create({ - model: 'palmyra-x-003-instruct', - prompt: 'Write me an SEO article about...', - }); + const responsePromise = client.completions.create({ model: 'palmyra-x-003-instruct', prompt: 'Write me an SEO article about...' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -24,15 +18,15 @@ describe('resource completions', () => { test('create: required and optional params', async () => { const response = await client.completions.create({ - model: 'palmyra-x-003-instruct', - prompt: 'Write me an SEO article about...', - best_of: 1, - max_tokens: 150, - random_seed: 42, - stop: ['.'], - stream: false, - temperature: 0.7, - top_p: 0.9, - }); + model: 'palmyra-x-003-instruct', + prompt: 'Write me an SEO article about...', + best_of: 1, + max_tokens: 150, + random_seed: 42, + stop: ['.'], + stream: false, + temperature: 0.7, + top_p: 0.9, + }); }); }); diff --git a/tests/api-resources/files.test.ts b/tests/api-resources/files.test.ts index 895c0ee6..159bffd6 100644 --- a/tests/api-resources/files.test.ts +++ b/tests/api-resources/files.test.ts @@ -2,10 +2,7 @@ import Writer, { toFile } from 'writer-sdk'; -const client = new Writer({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); +const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); describe('resource files', () => { test('retrieve', async () => { @@ -32,20 +29,17 @@ describe('resource files', () => { test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.files.list( - { - after: 'after', - before: 'before', - file_types: 'file_types', - graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - limit: 0, - order: 'asc', - status: 'in_progress', - }, - { path: '/_stainless_unknown_path' }, - ), - ).rejects.toThrow(Writer.NotFoundError); + await expect(client.files.list({ + after: 'after', + before: 'before', + file_types: 'file_types', + graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + limit: 0, + order: 'asc', + status: 'in_progress', + }, { path: '/_stainless_unknown_path' })) + .rejects + .toThrow(Writer.NotFoundError); }); test('delete', async () => { @@ -76,9 +70,7 @@ describe('resource files', () => { // requests with binary data not yet supported in test environment test.skip('upload: only required params', async () => { - const responsePromise = client.files.upload({ - content: await toFile(Buffer.from('Example data'), 'README.md'), - 'Content-Disposition': 'Content-Disposition', + const responsePromise = client.files.upload({ content: await toFile(Buffer.from('Example data'), 'README.md'), 'Content-Disposition': 'Content-Disposition', 'Content-Type': 'Content-Type', }); const rawResponse = await responsePromise.asResponse(); @@ -93,10 +85,10 @@ describe('resource files', () => { // requests with binary data not yet supported in test environment test.skip('upload: required and optional params', async () => { const response = await client.files.upload({ - content: await toFile(Buffer.from('Example data'), 'README.md'), - 'Content-Disposition': 'Content-Disposition', + content: await toFile(Buffer.from('Example data'), 'README.md'), + 'Content-Disposition': 'Content-Disposition', 'Content-Type': 'Content-Type', - graphId: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - }); + graphId: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + }); }); }); diff --git a/tests/api-resources/graphs.test.ts b/tests/api-resources/graphs.test.ts index 626f36b6..eed9e70f 100644 --- a/tests/api-resources/graphs.test.ts +++ b/tests/api-resources/graphs.test.ts @@ -2,10 +2,7 @@ import Writer from 'writer-sdk'; -const client = new Writer({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); +const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); describe('resource graphs', () => { test('create', async () => { @@ -54,17 +51,14 @@ describe('resource graphs', () => { test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.graphs.list( - { - after: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - before: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - limit: 0, - order: 'asc', - }, - { path: '/_stainless_unknown_path' }, - ), - ).rejects.toThrow(Writer.NotFoundError); + await expect(client.graphs.list({ + after: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + before: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + limit: 0, + order: 'asc', + }, { path: '/_stainless_unknown_path' })) + .rejects + .toThrow(Writer.NotFoundError); }); test('delete', async () => { @@ -79,9 +73,7 @@ describe('resource graphs', () => { }); test('addFileToGraph: only required params', async () => { - const responsePromise = client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { - file_id: 'file_id', - }); + const responsePromise = client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { file_id: 'file_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -92,16 +84,11 @@ describe('resource graphs', () => { }); test('addFileToGraph: required and optional params', async () => { - const response = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { - file_id: 'file_id', - }); + const response = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { file_id: 'file_id' }); }); test('question: only required params', async () => { - const responsePromise = client.graphs.question({ - graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], - question: 'question', - }); + const responsePromise = client.graphs.question({ graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], question: 'question' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -113,27 +100,25 @@ describe('resource graphs', () => { test('question: required and optional params', async () => { const response = await client.graphs.question({ - graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], - question: 'question', - query_config: { - grounding_level: 0, - inline_citations: true, - keyword_threshold: 0, - max_snippets: 1, - max_subquestions: 1, - max_tokens: 100, - search_weight: 0, - semantic_threshold: 0, - }, - stream: false, - subqueries: true, - }); + graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], + question: 'question', + query_config: { + grounding_level: 0, + inline_citations: true, + keyword_threshold: 0, + max_snippets: 1, + max_subquestions: 1, + max_tokens: 100, + search_weight: 0, + semantic_threshold: 0, + }, + stream: false, + subqueries: true, + }); }); test('removeFileFromGraph: only required params', async () => { - const responsePromise = client.graphs.removeFileFromGraph('file_id', { - graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - }); + const responsePromise = client.graphs.removeFileFromGraph('file_id', { graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -144,8 +129,6 @@ describe('resource graphs', () => { }); test('removeFileFromGraph: required and optional params', async () => { - const response = await client.graphs.removeFileFromGraph('file_id', { - graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - }); + const response = await client.graphs.removeFileFromGraph('file_id', { graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e' }); }); }); diff --git a/tests/api-resources/models.test.ts b/tests/api-resources/models.test.ts index ffe9b11d..f9a688b5 100644 --- a/tests/api-resources/models.test.ts +++ b/tests/api-resources/models.test.ts @@ -2,10 +2,7 @@ import Writer from 'writer-sdk'; -const client = new Writer({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); +const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); describe('resource models', () => { test('list', async () => { diff --git a/tests/api-resources/tools.test.ts b/tests/api-resources/tools.test.ts index 78f89f5a..c35e964a 100644 --- a/tests/api-resources/tools.test.ts +++ b/tests/api-resources/tools.test.ts @@ -2,10 +2,7 @@ import Writer from 'writer-sdk'; -const client = new Writer({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); +const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); describe('resource tools', () => { test('parsePdf: only required params', async () => { diff --git a/tests/api-resources/translation.test.ts b/tests/api-resources/translation.test.ts index 9098b182..22d62eb4 100644 --- a/tests/api-resources/translation.test.ts +++ b/tests/api-resources/translation.test.ts @@ -2,22 +2,19 @@ import Writer from 'writer-sdk'; -const client = new Writer({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); +const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); describe('resource translation', () => { test('translate: only required params', async () => { const responsePromise = client.translation.translate({ - formality: true, - length_control: true, - mask_profanity: true, - model: 'palmyra-translate', - source_language_code: 'en', - target_language_code: 'es', - text: 'Hello, world!', - }); + formality: true, + length_control: true, + mask_profanity: true, + model: 'palmyra-translate', + source_language_code: 'en', + target_language_code: 'es', + text: 'Hello, world!', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -29,13 +26,13 @@ describe('resource translation', () => { test('translate: required and optional params', async () => { const response = await client.translation.translate({ - formality: true, - length_control: true, - mask_profanity: true, - model: 'palmyra-translate', - source_language_code: 'en', - target_language_code: 'es', - text: 'Hello, world!', - }); + formality: true, + length_control: true, + mask_profanity: true, + model: 'palmyra-translate', + source_language_code: 'en', + target_language_code: 'es', + text: 'Hello, world!', + }); }); }); diff --git a/tests/api-resources/vision.test.ts b/tests/api-resources/vision.test.ts index 72b2795d..0b7ee56c 100644 --- a/tests/api-resources/vision.test.ts +++ b/tests/api-resources/vision.test.ts @@ -2,21 +2,15 @@ import Writer from 'writer-sdk'; -const client = new Writer({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); +const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); describe('resource vision', () => { test('analyze: only required params', async () => { const responsePromise = client.vision.analyze({ - model: 'palmyra-vision', - prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.', - variables: [ - { file_id: 'f1234', name: 'image_1' }, - { file_id: 'f9876', name: 'image_2' }, - ], - }); + model: 'palmyra-vision', + prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.', + variables: [{ file_id: 'f1234', name: 'image_1' }, { file_id: 'f9876', name: 'image_2' }], + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -28,12 +22,9 @@ describe('resource vision', () => { test('analyze: required and optional params', async () => { const response = await client.vision.analyze({ - model: 'palmyra-vision', - prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.', - variables: [ - { file_id: 'f1234', name: 'image_1' }, - { file_id: 'f9876', name: 'image_2' }, - ], - }); + model: 'palmyra-vision', + prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.', + variables: [{ file_id: 'f1234', name: 'image_1' }, { file_id: 'f9876', name: 'image_2' }], + }); }); }); diff --git a/tests/index.test.ts b/tests/index.test.ts index ab852e55..e6060dec 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -21,10 +21,10 @@ describe('instantiate client', () => { describe('defaultHeaders', () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - defaultHeaders: { 'X-My-Default-Header': '2' }, - apiKey: 'My API Key', - }); + baseURL: 'http://localhost:5000/', + defaultHeaders: { 'X-My-Default-Header': '2' }, + apiKey: 'My API Key', +}) test('they are used in the request', async () => { const { req } = await client.buildRequest({ path: '/foo', method: 'post' }); @@ -49,193 +49,191 @@ describe('instantiate client', () => { expect(req.headers.has('x-my-default-header')).toBe(false); }); }); - describe('logging', () => { - const env = process.env; +describe('logging', () => { + const env = process.env; - beforeEach(() => { - process.env = { ...env }; - process.env['WRITER_LOG'] = undefined; - }); + beforeEach(() => { + process.env = { ...env }; + process.env['WRITER_LOG'] = undefined; + }); - afterEach(() => { - process.env = env; - }); + afterEach(() => { + process.env = env; + }); - const forceAPIResponseForClient = async (client: Writer) => { - await new APIPromise( - client, - Promise.resolve({ - response: new Response(), - controller: new AbortController(), - requestLogID: 'log_000000', - retryOfRequestLogID: undefined, - startTime: Date.now(), - options: { - method: 'get', - path: '/', - }, - }), - ); + const forceAPIResponseForClient = async (client: Writer) => { + await new APIPromise( + client, + Promise.resolve({ + response: new Response(), + controller: new AbortController(), + requestLogID: 'log_000000', + retryOfRequestLogID: undefined, + startTime: Date.now(), + options: { + method: 'get', + path: '/', + }, + }), + ); + }; + + test('debug logs when log level is debug', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), }; - test('debug logs when log level is debug', async () => { - const debugMock = jest.fn(); - const logger = { - debug: debugMock, - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; - - const client = new Writer({ - logger: logger, - logLevel: 'debug', - apiKey: 'My API Key', - }); + const client = new Writer({ + logger: logger, + logLevel: 'debug', + apiKey: 'My API Key', +}); - await forceAPIResponseForClient(client); - expect(debugMock).toHaveBeenCalled(); - }); + await forceAPIResponseForClient(client); + expect(debugMock).toHaveBeenCalled(); + }); - test('default logLevel is warn', async () => { - const client = new Writer({ apiKey: 'My API Key' }); - expect(client.logLevel).toBe('warn'); - }); + test('default logLevel is warn', async () => { + const client = new Writer({ apiKey: 'My API Key' }); + expect(client.logLevel).toBe('warn'); + }); - test('debug logs are skipped when log level is info', async () => { - const debugMock = jest.fn(); - const logger = { - debug: debugMock, - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; + test('debug logs are skipped when log level is info', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; - const client = new Writer({ - logger: logger, - logLevel: 'info', - apiKey: 'My API Key', - }); + const client = new Writer({ + logger: logger, + logLevel: 'info', + apiKey: 'My API Key', +}); - await forceAPIResponseForClient(client); - expect(debugMock).not.toHaveBeenCalled(); - }); + await forceAPIResponseForClient(client); + expect(debugMock).not.toHaveBeenCalled(); + }); - test('debug logs happen with debug env var', async () => { - const debugMock = jest.fn(); - const logger = { - debug: debugMock, - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; + test('debug logs happen with debug env var', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; - process.env['WRITER_LOG'] = 'debug'; - const client = new Writer({ logger: logger, apiKey: 'My API Key' }); - expect(client.logLevel).toBe('debug'); + process.env['WRITER_LOG'] = 'debug'; + const client = new Writer({ logger: logger, apiKey: 'My API Key' }); + expect(client.logLevel).toBe('debug'); - await forceAPIResponseForClient(client); - expect(debugMock).toHaveBeenCalled(); - }); + await forceAPIResponseForClient(client); + expect(debugMock).toHaveBeenCalled(); + }); - test('warn when env var level is invalid', async () => { - const warnMock = jest.fn(); - const logger = { - debug: jest.fn(), - info: jest.fn(), - warn: warnMock, - error: jest.fn(), - }; + test('warn when env var level is invalid', async () => { + const warnMock = jest.fn(); + const logger = { + debug: jest.fn(), + info: jest.fn(), + warn: warnMock, + error: jest.fn(), + }; - process.env['WRITER_LOG'] = 'not a log level'; - const client = new Writer({ logger: logger, apiKey: 'My API Key' }); - expect(client.logLevel).toBe('warn'); - expect(warnMock).toHaveBeenCalledWith( - 'process.env[\'WRITER_LOG\'] was set to "not a log level", expected one of ["off","error","warn","info","debug"]', - ); - }); + process.env['WRITER_LOG'] = 'not a log level'; + const client = new Writer({ logger: logger, apiKey: 'My API Key' }); + expect(client.logLevel).toBe('warn'); + expect(warnMock).toHaveBeenCalledWith('process.env[\'WRITER_LOG\'] was set to "not a log level", expected one of ["off","error","warn","info","debug"]'); + }); - test('client log level overrides env var', async () => { - const debugMock = jest.fn(); - const logger = { - debug: debugMock, - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; + test('client log level overrides env var', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; - process.env['WRITER_LOG'] = 'debug'; - const client = new Writer({ - logger: logger, - logLevel: 'off', - apiKey: 'My API Key', - }); + process.env['WRITER_LOG'] = 'debug'; + const client = new Writer({ + logger: logger, + logLevel: 'off', + apiKey: 'My API Key', +}); - await forceAPIResponseForClient(client); - expect(debugMock).not.toHaveBeenCalled(); - }); + await forceAPIResponseForClient(client); + expect(debugMock).not.toHaveBeenCalled(); + }); - test('no warning logged for invalid env var level + valid client level', async () => { - const warnMock = jest.fn(); - const logger = { - debug: jest.fn(), - info: jest.fn(), - warn: warnMock, - error: jest.fn(), - }; + test('no warning logged for invalid env var level + valid client level', async () => { + const warnMock = jest.fn(); + const logger = { + debug: jest.fn(), + info: jest.fn(), + warn: warnMock, + error: jest.fn(), + }; - process.env['WRITER_LOG'] = 'not a log level'; - const client = new Writer({ - logger: logger, - logLevel: 'debug', - apiKey: 'My API Key', - }); - expect(client.logLevel).toBe('debug'); - expect(warnMock).not.toHaveBeenCalled(); - }); + process.env['WRITER_LOG'] = 'not a log level'; + const client = new Writer({ + logger: logger, + logLevel: 'debug', + apiKey: 'My API Key', +}); + expect(client.logLevel).toBe('debug'); + expect(warnMock).not.toHaveBeenCalled(); }); +}); describe('defaultQuery', () => { test('with null query params given', () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - defaultQuery: { apiVersion: 'foo' }, - apiKey: 'My API Key', - }); + baseURL: 'http://localhost:5000/', + defaultQuery: { apiVersion: 'foo' }, + apiKey: 'My API Key', +}); expect(client.buildURL('/foo', null)).toEqual('http://localhost:5000/foo?apiVersion=foo'); }); test('multiple default query params', () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - defaultQuery: { apiVersion: 'foo', hello: 'world' }, - apiKey: 'My API Key', - }); + baseURL: 'http://localhost:5000/', + defaultQuery: { apiVersion: 'foo', hello: 'world' }, + apiKey: 'My API Key', +}); expect(client.buildURL('/foo', null)).toEqual('http://localhost:5000/foo?apiVersion=foo&hello=world'); }); test('overriding with `undefined`', () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - defaultQuery: { hello: 'world' }, - apiKey: 'My API Key', - }); + baseURL: 'http://localhost:5000/', + defaultQuery: { hello: 'world' }, + apiKey: 'My API Key', +}) expect(client.buildURL('/foo', { hello: undefined })).toEqual('http://localhost:5000/foo'); }); }); test('custom fetch', async () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - apiKey: 'My API Key', - fetch: (url) => { - return Promise.resolve( - new Response(JSON.stringify({ url, custom: true }), { - headers: { 'Content-Type': 'application/json' }, - }), - ); - }, - }); + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + fetch: (url) => { + return Promise.resolve( + new Response(JSON.stringify({ url, custom: true }), { + headers: { 'Content-Type': 'application/json' }, + }), + ); +}, +}); const response = await client.get('/foo'); expect(response).toEqual({ url: 'http://localhost:5000/foo', custom: true }); @@ -244,35 +242,37 @@ describe('instantiate client', () => { test('explicit global fetch', async () => { // make sure the global fetch type is assignable to our Fetch type const client = new Writer({ - baseURL: 'http://localhost:5000/', - apiKey: 'My API Key', - fetch: defaultFetch, - }); + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + fetch: defaultFetch, +}); }); test('custom signal', async () => { const client = new Writer({ - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', - apiKey: 'My API Key', - fetch: (...args) => { - return new Promise((resolve, reject) => - setTimeout( - () => - defaultFetch(...args) - .then(resolve) - .catch(reject), - 300, - ), - ); - }, - }); + baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010', + apiKey: 'My API Key', + fetch: (...args) => { + return new Promise((resolve, reject) => + setTimeout( + () => + defaultFetch(...args) + .then(resolve) + .catch(reject), + 300, + ), + ); +}, +}); const controller = new AbortController(); setTimeout(() => controller.abort(), 200); const spy = jest.spyOn(client, 'request'); - await expect(client.get('/foo', { signal: controller.signal })).rejects.toThrowError(APIUserAbortError); + await expect(client.get('/foo', { signal: controller.signal })).rejects.toThrowError( + APIUserAbortError, + ); expect(spy).toHaveBeenCalledTimes(1); }); @@ -284,10 +284,10 @@ describe('instantiate client', () => { }; const client = new Writer({ - baseURL: 'http://localhost:5000/', - apiKey: 'My API Key', - fetch: testFetch, - }); + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + fetch: testFetch, +}); await client.patch('/foo'); expect(capturedRequest?.method).toEqual('PATCH'); @@ -322,35 +322,29 @@ describe('instantiate client', () => { test('empty env variable', () => { process.env['WRITER_BASE_URL'] = ''; // empty const client = new Writer({ apiKey: 'My API Key' }); - expect(client.baseURL).toEqual('https://api.writer.com'); + expect(client.baseURL).toEqual('https://api.writer.com') }); test('blank env variable', () => { process.env['WRITER_BASE_URL'] = ' '; // blank const client = new Writer({ apiKey: 'My API Key' }); - expect(client.baseURL).toEqual('https://api.writer.com'); + expect(client.baseURL).toEqual('https://api.writer.com') }); test('in request options', () => { const client = new Writer({ apiKey: 'My API Key' }); - expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual( - 'http://localhost:5000/option/foo', - ); + expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual('http://localhost:5000/option/foo'); }); test('in request options overridden by client options', () => { const client = new Writer({ apiKey: 'My API Key', baseURL: 'http://localhost:5000/client' }); - expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual( - 'http://localhost:5000/client/foo', - ); + expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual('http://localhost:5000/client/foo'); }); test('in request options overridden by env variable', () => { process.env['WRITER_BASE_URL'] = 'http://localhost:5000/env'; const client = new Writer({ apiKey: 'My API Key' }); - expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual( - 'http://localhost:5000/env/foo', - ); + expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual('http://localhost:5000/env/foo'); }); }); @@ -366,10 +360,10 @@ describe('instantiate client', () => { describe('withOptions', () => { test('creates a new client with overridden options', async () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - maxRetries: 3, - apiKey: 'My API Key', - }); + baseURL: 'http://localhost:5000/', + maxRetries: 3, + apiKey: 'My API Key', + }); const newClient = client.withOptions({ maxRetries: 5, @@ -391,11 +385,11 @@ describe('instantiate client', () => { test('inherits options from the parent client', async () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - defaultHeaders: { 'X-Test-Header': 'test-value' }, - defaultQuery: { 'test-param': 'test-value' }, - apiKey: 'My API Key', - }); + baseURL: 'http://localhost:5000/', + defaultHeaders: { 'X-Test-Header': 'test-value' }, + defaultQuery: { 'test-param': 'test-value' }, + apiKey: 'My API Key', + }); const newClient = client.withOptions({ baseURL: 'http://localhost:5001/', @@ -410,10 +404,10 @@ describe('instantiate client', () => { test('respects runtime property changes when creating new client', () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - timeout: 1000, - apiKey: 'My API Key', - }); + baseURL: 'http://localhost:5000/', + timeout: 1000, + apiKey: 'My API Key', + }); // Modify the client properties directly after creation client.baseURL = 'http://localhost:6000/'; @@ -459,18 +453,13 @@ describe('request building', () => { describe('custom headers', () => { test('handles undefined', async () => { - const { req } = await client.buildRequest({ - path: '/foo', - method: 'post', - body: { value: 'hello' }, - headers: { 'X-Foo': 'baz', 'x-foo': 'bar', 'x-Foo': undefined, 'x-baz': 'bam', 'X-Baz': null }, - }); + const { req } = await client.buildRequest({ path: '/foo', method: 'post', body: { value: 'hello' }, headers: { 'X-Foo': 'baz', 'x-foo': 'bar', 'x-Foo': undefined, 'x-baz': 'bam', 'X-Baz': null } }); expect(req.headers.get('x-foo')).toEqual('bar'); expect(req.headers.get('x-Foo')).toEqual('bar'); expect(req.headers.get('X-Foo')).toEqual('bar'); expect(req.headers.get('x-baz')).toEqual(null); }); - }); + }) }); describe('default encoder', () => { @@ -547,40 +536,37 @@ describe('default encoder', () => { describe('retries', () => { test('retry on timeout', async () => { let count = 0; - const testFetch = async ( - url: string | URL | Request, - { signal }: RequestInit = {}, - ): Promise => { - if (count++ === 0) { - return new Promise( - (resolve, reject) => signal?.addEventListener('abort', () => reject(new Error('timed out'))), - ); - } - return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); - }; - - const client = new Writer({ - apiKey: 'My API Key', - timeout: 10, - fetch: testFetch, - }); + const testFetch = async (url: string | URL | Request, { signal }: RequestInit = {}): Promise => { + if (count++ === 0) { + return new Promise((resolve, reject) => + signal?.addEventListener('abort', () => reject(new Error('timed out'))), + ); + } + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; - expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); - expect(count).toEqual(2); - expect( - await client - .request({ path: '/foo', method: 'get' }) - .asResponse() - .then((r) => r.text()), - ).toEqual(JSON.stringify({ a: 1 })); - expect(count).toEqual(3); + const client = new Writer({ + apiKey: 'My API Key', + timeout: 10, + fetch: testFetch, }); + expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); + expect(count).toEqual(2); + expect( + await client + .request({ path: '/foo', method: 'get' }) + .asResponse() + .then((r) => r.text()), + ).toEqual(JSON.stringify({ a: 1 })); + expect(count).toEqual(3); + }); + test('retry count header', async () => { let count = 0; let capturedRequest: RequestInit | undefined; const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { - count++; + count++ if (count <= 2) { return new Response(undefined, { status: 429, @@ -594,10 +580,10 @@ describe('retries', () => { }; const client = new Writer({ - apiKey: 'My API Key', - fetch: testFetch, - maxRetries: 4, - }); + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + }); expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); @@ -609,7 +595,7 @@ describe('retries', () => { let count = 0; let capturedRequest: RequestInit | undefined; const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { - count++; + count++ if (count <= 2) { return new Response(undefined, { status: 429, @@ -622,10 +608,10 @@ describe('retries', () => { return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; const client = new Writer({ - apiKey: 'My API Key', - fetch: testFetch, - maxRetries: 4, - }); + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + }); expect( await client.request({ @@ -642,7 +628,7 @@ describe('retries', () => { let count = 0; let capturedRequest: RequestInit | undefined; const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { - count++; + count++ if (count <= 2) { return new Response(undefined, { status: 429, @@ -655,11 +641,11 @@ describe('retries', () => { return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; const client = new Writer({ - apiKey: 'My API Key', - fetch: testFetch, - maxRetries: 4, - defaultHeaders: { 'X-Stainless-Retry-Count': null }, - }); + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + defaultHeaders: { 'X-Stainless-Retry-Count': null }, + }); expect( await client.request({ @@ -675,7 +661,7 @@ describe('retries', () => { let count = 0; let capturedRequest: RequestInit | undefined; const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { - count++; + count++ if (count <= 2) { return new Response(undefined, { status: 429, @@ -688,10 +674,10 @@ describe('retries', () => { return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; const client = new Writer({ - apiKey: 'My API Key', - fetch: testFetch, - maxRetries: 4, - }); + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + }); expect( await client.request({ @@ -706,10 +692,7 @@ describe('retries', () => { test('retry on 429 with retry-after', async () => { let count = 0; - const testFetch = async ( - url: string | URL | Request, - { signal }: RequestInit = {}, - ): Promise => { + const testFetch = async (url: string | URL | Request, { signal }: RequestInit = {}): Promise => { if (count++ === 0) { return new Response(undefined, { status: 429, @@ -736,10 +719,7 @@ describe('retries', () => { test('retry on 429 with retry-after-ms', async () => { let count = 0; - const testFetch = async ( - url: string | URL | Request, - { signal }: RequestInit = {}, - ): Promise => { + const testFetch = async (url: string | URL | Request, { signal }: RequestInit = {}): Promise => { if (count++ === 0) { return new Response(undefined, { status: 429, diff --git a/tests/streaming.test.ts b/tests/streaming.test.ts index 34d28755..2915814b 100644 --- a/tests/streaming.test.ts +++ b/tests/streaming.test.ts @@ -242,4 +242,4 @@ test('error handling', async () => { `[Error: {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}]`, ); await err.toBeInstanceOf(APIError); -}); +});; diff --git a/tests/stringifyQuery.test.ts b/tests/stringifyQuery.test.ts index 90cf3c26..75691ca8 100644 --- a/tests/stringifyQuery.test.ts +++ b/tests/stringifyQuery.test.ts @@ -2,26 +2,24 @@ import { stringifyQuery } from 'writer-sdk/internal/utils/query'; -describe(stringifyQuery, () => { - for (const [input, expected] of [ - [{ a: '1', b: 2, c: true }, 'a=1&b=2&c=true'], - [{ a: null, b: false, c: undefined }, 'a=&b=false'], - [{ 'a/b': 1.28341 }, `${encodeURIComponent('a/b')}=1.28341`], - [ - { 'a/b': 'c/d', 'e=f': 'g&h' }, - `${encodeURIComponent('a/b')}=${encodeURIComponent('c/d')}&${encodeURIComponent( - 'e=f', - )}=${encodeURIComponent('g&h')}`, - ], - ] as const) { - it(`${JSON.stringify(input)} -> ${expected}`, () => { - expect(stringifyQuery(input)).toEqual(expected); - }); - } +describe(stringifyQuery, () => { for (const [input, expected] of [ + [{ a: '1', b: 2, c: true }, 'a=1&b=2&c=true'], + [{ a: null, b: false, c: undefined }, 'a=&b=false'], + [{ 'a/b': 1.28341 }, `${encodeURIComponent('a/b')}=1.28341`], + [ + { 'a/b': 'c/d', 'e=f': 'g&h' }, + `${encodeURIComponent('a/b')}=${encodeURIComponent('c/d')}&${encodeURIComponent( + 'e=f', + )}=${encodeURIComponent('g&h')}`, + ], +] as const) { + it(`${JSON.stringify(input)} -> ${expected}`, () => { + expect(stringifyQuery(input)).toEqual(expected); + }); +} - for (const value of [[], {}, new Date()]) { - it(`${JSON.stringify(value)} -> `, () => { - expect(() => stringifyQuery({ value })).toThrow(`Cannot stringify type ${typeof value}`); - }); - } -}); +for (const value of [[], {}, new Date()]) { + it(`${JSON.stringify(value)} -> `, () => { + expect(() => stringifyQuery({ value })).toThrow(`Cannot stringify type ${typeof value}`); + }); +} }) diff --git a/yarn.lock b/yarn.lock index 894a1b79..80ed97d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -709,11 +709,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@pkgr/core@^0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c" - integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw== - "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -1515,14 +1510,6 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-plugin-prettier@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.1.tgz#99b55d7dd70047886b2222fdd853665f180b36af" - integrity sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg== - dependencies: - prettier-linter-helpers "^1.0.0" - synckit "^0.11.7" - eslint-plugin-unused-imports@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz#62ddc7446ccbf9aa7b6f1f0b00a980423cda2738" @@ -1681,11 +1668,6 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-diff@^1.1.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" - integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== - fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" @@ -2852,14 +2834,6 @@ prelude-ls@^1.2.1: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== - -prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - prettier@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.1.tgz#6ba9f23165d690b6cbdaa88cb0807278f7019848" @@ -3161,13 +3135,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -synckit@^0.11.7: - version "0.11.8" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.8.tgz#b2aaae998a4ef47ded60773ad06e7cb821f55457" - integrity sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A== - dependencies: - "@pkgr/core" "^0.2.4" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" From 7f46854adff49ae46df71380fb8a40cd0879c4ae Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 21:46:47 +0000 Subject: [PATCH 06/22] chore(internal): codegen related update --- eslint.config.mjs | 3 + package.json | 1 + packages/mcp-server/jest.config.ts | 4 +- packages/mcp-server/src/auth.ts | 46 +- packages/mcp-server/src/code-tool-types.ts | 2 +- packages/mcp-server/src/code-tool-worker.ts | 78 +- packages/mcp-server/src/code-tool.ts | 136 +- packages/mcp-server/src/docs-search-tool.ts | 55 +- packages/mcp-server/src/http.ts | 68 +- packages/mcp-server/src/index.ts | 2 +- packages/mcp-server/src/instructions.ts | 20 +- packages/mcp-server/src/local-docs-search.ts | 1994 +++++++++-------- packages/mcp-server/src/methods.ts | 359 +-- packages/mcp-server/src/options.ts | 47 +- packages/mcp-server/src/server.ts | 104 +- packages/mcp-server/src/types.ts | 80 +- scripts/fast-format | 6 +- scripts/format | 3 +- scripts/lint | 3 - scripts/utils/postprocess-files.cjs | 9 +- src/api-promise.ts | 2 +- src/client.ts | 494 ++-- src/core/api-promise.ts | 9 +- src/core/error.ts | 46 +- src/core/pagination.ts | 43 +- src/core/streaming.ts | 26 +- src/error.ts | 2 +- src/index.ts | 16 +- src/internal/builtin-types.ts | 23 +- src/internal/detect-platform.ts | 6 +- src/internal/errors.ts | 14 +- src/internal/headers.ts | 4 +- src/internal/parse.ts | 11 +- src/internal/request-options.ts | 7 +- src/internal/shim-types.ts | 4 +- src/internal/shims.ts | 4 +- src/internal/to-file.ts | 14 +- src/internal/types.ts | 50 +- src/internal/utils/log.ts | 37 +- src/internal/utils/uuid.ts | 8 +- src/pagination.ts | 2 +- src/resource.ts | 2 +- src/resources/applications/applications.ts | 83 +- src/resources/applications/graphs.ts | 8 +- src/resources/applications/index.ts | 26 +- src/resources/applications/jobs.ts | 23 +- src/resources/chat.ts | 24 +- src/resources/completions.ts | 29 +- src/resources/files.ts | 24 +- src/resources/graphs.ts | 77 +- src/resources/index.ts | 88 +- src/resources/models.ts | 4 +- src/resources/shared.ts | 10 +- src/resources/tools.ts | 176 +- src/resources/translation.ts | 2 +- src/resources/vision.ts | 2 +- src/streaming.ts | 2 +- src/uploads.ts | 2 +- src/version.ts | 2 +- .../applications/applications.test.ts | 35 +- .../api-resources/applications/graphs.test.ts | 13 +- tests/api-resources/applications/jobs.test.ts | 31 +- tests/api-resources/chat.test.ts | 134 +- tests/api-resources/completions.test.ts | 30 +- tests/api-resources/files.test.ts | 42 +- tests/api-resources/graphs.test.ts | 75 +- tests/api-resources/models.test.ts | 5 +- tests/api-resources/tools.test.ts | 5 +- tests/api-resources/translation.test.ts | 37 +- tests/api-resources/vision.test.ts | 27 +- tests/index.test.ts | 498 ++-- tests/streaming.test.ts | 2 +- tests/stringifyQuery.test.ts | 42 +- yarn.lock | 41 +- 74 files changed, 3223 insertions(+), 2220 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index edd23b90..3954b642 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,6 +1,7 @@ // @ts-check import tseslint from 'typescript-eslint'; import unusedImports from 'eslint-plugin-unused-imports'; +import prettier from 'eslint-plugin-prettier'; export default tseslint.config( { @@ -13,9 +14,11 @@ export default tseslint.config( plugins: { '@typescript-eslint': tseslint.plugin, 'unused-imports': unusedImports, + prettier, }, rules: { 'no-unused-vars': 'off', + 'prettier/prettier': 'error', 'unused-imports/no-unused-imports': 'error', 'no-restricted-imports': [ 'error', diff --git a/package.json b/package.json index 8419e108..b824c951 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "@typescript-eslint/eslint-plugin": "8.31.1", "@typescript-eslint/parser": "8.31.1", "eslint": "^9.39.1", + "eslint-plugin-prettier": "^5.4.1", "eslint-plugin-unused-imports": "^4.1.4", "fast-check": "^3.23.1", "iconv-lite": "^0.6.3", diff --git a/packages/mcp-server/jest.config.ts b/packages/mcp-server/jest.config.ts index 359e7f4d..3080925d 100644 --- a/packages/mcp-server/jest.config.ts +++ b/packages/mcp-server/jest.config.ts @@ -10,9 +10,7 @@ const config: JestConfigWithTsJest = { '^writer-sdk-mcp$': '/src/index.ts', '^writer-sdk-mcp/(.*)$': '/src/$1', }, - modulePathIgnorePatterns: [ - '/dist/', - ], + modulePathIgnorePatterns: ['/dist/'], testPathIgnorePatterns: ['scripts'], }; diff --git a/packages/mcp-server/src/auth.ts b/packages/mcp-server/src/auth.ts index b796c977..495e9823 100644 --- a/packages/mcp-server/src/auth.ts +++ b/packages/mcp-server/src/auth.ts @@ -1,34 +1,42 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { IncomingMessage } from 'node:http' -import { ClientOptions } from 'writer-sdk' +import { IncomingMessage } from 'node:http'; +import { ClientOptions } from 'writer-sdk'; import { McpOptions } from './options'; -export const parseClientAuthHeaders = (req: IncomingMessage, required?: boolean): Partial => { if (req.headers.authorization) { - const scheme = req.headers.authorization.split(" ")[0]!; - const value = req.headers.authorization.slice(scheme.length + 1); - switch (scheme) { - case 'Bearer': - return { apiKey: req.headers.authorization.slice("Bearer ".length) }; - default: - throw new Error('Unsupported authorization scheme. Expected the "Authorization" header to be a supported scheme (Bearer).'); +export const parseClientAuthHeaders = (req: IncomingMessage, required?: boolean): Partial => { + if (req.headers.authorization) { + const scheme = req.headers.authorization.split(' ')[0]!; + const value = req.headers.authorization.slice(scheme.length + 1); + switch (scheme) { + case 'Bearer': + return { apiKey: req.headers.authorization.slice('Bearer '.length) }; + default: + throw new Error( + 'Unsupported authorization scheme. Expected the "Authorization" header to be a supported scheme (Bearer).', + ); + } + } else if (required) { + throw new Error('Missing required Authorization header; see WWW-Authenticate header for details.'); } -} else if (required) { - throw new Error('Missing required Authorization header; see WWW-Authenticate header for details.'); -} -const apiKey = Array.isArray(req.headers['x-writer-api-key']) ? req.headers['x-writer-api-key'][0] : req.headers['x-writer-api-key'] -return {apiKey}; } + const apiKey = + Array.isArray(req.headers['x-writer-api-key']) ? + req.headers['x-writer-api-key'][0] + : req.headers['x-writer-api-key']; + return { apiKey }; +}; export const getStainlessApiKey = (req: IncomingMessage, mcpOptions: McpOptions): string | undefined => { // Try to get the key from the x-stainless-api-key header - const headerKey = Array.isArray(req.headers['x-stainless-api-key']) ? - req.headers['x-stainless-api-key'][0] - : req.headers['x-stainless-api-key']; + const headerKey = + Array.isArray(req.headers['x-stainless-api-key']) ? + req.headers['x-stainless-api-key'][0] + : req.headers['x-stainless-api-key']; if (headerKey && typeof headerKey === 'string') { return headerKey; } // Fall back to value set in the mcpOptions (e.g. from environment variable), if provided return mcpOptions.stainlessApiKey; -} +}; diff --git a/packages/mcp-server/src/code-tool-types.ts b/packages/mcp-server/src/code-tool-types.ts index f0b33c22..ace4d54e 100644 --- a/packages/mcp-server/src/code-tool-types.ts +++ b/packages/mcp-server/src/code-tool-types.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { ClientOptions } from 'writer-sdk' +import { ClientOptions } from 'writer-sdk'; export type WorkerInput = { project_name: string; diff --git a/packages/mcp-server/src/code-tool-worker.ts b/packages/mcp-server/src/code-tool-worker.ts index 979445fb..332af849 100644 --- a/packages/mcp-server/src/code-tool-worker.ts +++ b/packages/mcp-server/src/code-tool-worker.ts @@ -59,8 +59,8 @@ function getTSDiagnostics(code: string): string[] { const codeWithImport = [ 'import { Writer } from "writer-sdk";', functionSource.type === 'declaration' ? - `async function run(${functionSource.client}: Writer)` : - `const run: (${functionSource.client}: Writer) => Promise =`, + `async function run(${functionSource.client}: Writer)` + : `const run: (${functionSource.client}: Writer) => Promise =`, functionSource.code, ].join('\n'); const sourcePath = path.resolve('code.ts'); @@ -108,36 +108,36 @@ function getTSDiagnostics(code: string): string[] { const fuse = new Fuse( [ - "client.applications.generateContent", - "client.applications.list", - "client.applications.retrieve", - "client.applications.jobs.create", - "client.applications.jobs.list", - "client.applications.jobs.retrieve", - "client.applications.jobs.retry", - "client.applications.graphs.list", - "client.applications.graphs.update", - "client.chat.chat", - "client.completions.create", - "client.models.list", - "client.graphs.addFileToGraph", - "client.graphs.create", - "client.graphs.delete", - "client.graphs.list", - "client.graphs.question", - "client.graphs.removeFileFromGraph", - "client.graphs.retrieve", - "client.graphs.update", - "client.files.delete", - "client.files.download", - "client.files.list", - "client.files.retrieve", - "client.files.retry", - "client.files.upload", - "client.tools.parsePdf", - "client.tools.webSearch", - "client.translation.translate", - "client.vision.analyze" + 'client.applications.generateContent', + 'client.applications.list', + 'client.applications.retrieve', + 'client.applications.jobs.create', + 'client.applications.jobs.list', + 'client.applications.jobs.retrieve', + 'client.applications.jobs.retry', + 'client.applications.graphs.list', + 'client.applications.graphs.update', + 'client.chat.chat', + 'client.completions.create', + 'client.models.list', + 'client.graphs.addFileToGraph', + 'client.graphs.create', + 'client.graphs.delete', + 'client.graphs.list', + 'client.graphs.question', + 'client.graphs.removeFileFromGraph', + 'client.graphs.retrieve', + 'client.graphs.update', + 'client.files.delete', + 'client.files.download', + 'client.files.list', + 'client.files.retrieve', + 'client.files.retry', + 'client.files.upload', + 'client.tools.parsePdf', + 'client.tools.webSearch', + 'client.translation.translate', + 'client.vision.analyze', ], { threshold: 1, shouldSort: true }, ); @@ -220,7 +220,12 @@ function parseError(code: string, error: unknown): string | undefined { // Deno uses V8; the first ":LINE:COLUMN" is the top of stack. const lineNumber = error.stack?.match(/:([0-9]+):[0-9]+/)?.[1]; // -1 for the zero-based indexing - const line = lineNumber && code.split('\n').at(parseInt(lineNumber, 10) - 1)?.trim(); + const line = + lineNumber && + code + .split('\n') + .at(parseInt(lineNumber, 10) - 1) + ?.trim(); return line ? `${message}\n at line ${lineNumber}\n ${line}` : message; } catch { return message; @@ -232,8 +237,9 @@ const fetch = async (req: Request): Promise => { const runFunctionSource = code ? getRunFunctionSource(code) : null; if (!runFunctionSource) { - const message = code - ? 'The code is missing a top-level `run` function.' + const message = + code ? + 'The code is missing a top-level `run` function.' : 'The code argument is missing. Provide one containing a top-level `run` function.'; return Response.json( { @@ -278,7 +284,7 @@ const fetch = async (req: Request): Promise => { try { let run_ = async (client: any) => {}; run_ = (await tseval(`${code}\nexport default run;`)).default; - const result = await run_(makeSdkProxy(client, { path: ["client"] })); + const result = await run_(makeSdkProxy(client, { path: ['client'] })); return Response.json({ is_error: false, result, diff --git a/packages/mcp-server/src/code-tool.ts b/packages/mcp-server/src/code-tool.ts index b1a9bd22..df578364 100644 --- a/packages/mcp-server/src/code-tool.ts +++ b/packages/mcp-server/src/code-tool.ts @@ -1,8 +1,16 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { ContentBlock, McpRequestContext, McpTool, Metadata, ToolCallResult, asErrorResult, asTextContentResult } from './types'; +import { + ContentBlock, + McpRequestContext, + McpTool, + Metadata, + ToolCallResult, + asErrorResult, + asTextContentResult, +} from './types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import { readEnv, requireValue } from "./util"; +import { readEnv, requireValue } from './util'; import { WorkerInput, WorkerOutput } from './code-tool-types'; import { getLogger } from './logger'; import { SdkMethod } from './methods'; @@ -44,10 +52,13 @@ Always type dynamic key-value stores explicitly as Record * @param codeExecutionMode - Whether to execute code in a local Deno environment or in a remote * sandbox environment hosted by Stainless. */ -export function codeTool( - {blockedMethods, codeExecutionMode}: - {blockedMethods: SdkMethod[] | undefined, codeExecutionMode: McpCodeExecutionMode}, -): McpTool { +export function codeTool({ + blockedMethods, + codeExecutionMode, +}: { + blockedMethods: SdkMethod[] | undefined; + codeExecutionMode: McpCodeExecutionMode; +}): McpTool { const metadata: Metadata = { resource: 'all', operation: 'write', tags: [] }; const tool: Tool = { name: 'execute', @@ -70,10 +81,13 @@ export function codeTool( const logger = getLogger(); - const handler = async ( - {reqContext, args}: - {reqContext: McpRequestContext, args: any}, - ): Promise => { + const handler = async ({ + reqContext, + args, + }: { + reqContext: McpRequestContext; + args: any; + }): Promise => { const code = args.code as string; // Do very basic blocking of code that includes forbidden method names. // @@ -83,7 +97,11 @@ export function codeTool( if (blockedMethods) { const blockedMatches = blockedMethods.filter((method) => code.includes(method.fullyQualifiedName)); if (blockedMatches.length > 0) { - return asErrorResult(`The following methods have been blocked by the MCP server and cannot be used in code execution: ${blockedMatches.map((m) => m.fullyQualifiedName).join(', ')}`); + return asErrorResult( + `The following methods have been blocked by the MCP server and cannot be used in code execution: ${blockedMatches + .map((m) => m.fullyQualifiedName) + .join(', ')}`, + ); } } @@ -108,35 +126,44 @@ export function codeTool( 'Got code tool execution result', ); return result; - } + }; return { metadata, tool, handler }; } -const remoteStainlessHandler = async ( - {reqContext, args}: - {reqContext: McpRequestContext, args: any}, -): Promise => { +const remoteStainlessHandler = async ({ + reqContext, + args, +}: { + reqContext: McpRequestContext; + args: any; +}): Promise => { const code = args.code as string; const intent = args.intent as string | undefined; const client = reqContext.client; - const codeModeEndpoint = readEnv("CODE_MODE_ENDPOINT_URL") ?? "https://api.stainless.com/api/ai/code-tool"; + const codeModeEndpoint = readEnv('CODE_MODE_ENDPOINT_URL') ?? 'https://api.stainless.com/api/ai/code-tool'; - const localClientEnvs = { WRITER_API_KEY: requireValue(readEnv('WRITER_API_KEY') ?? client.apiKey, 'set WRITER_API_KEY environment variable or provide apiKey client option'), WRITER_BASE_URL: readEnv('WRITER_BASE_URL') ?? client.baseURL ?? undefined }; + const localClientEnvs = { + WRITER_API_KEY: requireValue( + readEnv('WRITER_API_KEY') ?? client.apiKey, + 'set WRITER_API_KEY environment variable or provide apiKey client option', + ), + WRITER_BASE_URL: readEnv('WRITER_BASE_URL') ?? client.baseURL ?? undefined, + }; // Merge any upstream client envs from the request header, with upstream values taking precedence. const mergedClientEnvs = { ...localClientEnvs, ...reqContext.upstreamClientEnvs }; // Setting a Stainless API key authenticates requests to the code tool endpoint. const res = await fetch(codeModeEndpoint, { - method: "POST", + method: 'POST', headers: { - ...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey, }), - "Content-Type": "application/json", - "x-stainless-mcp-client-envs": JSON.stringify(mergedClientEnvs), + ...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey }), + 'Content-Type': 'application/json', + 'x-stainless-mcp-client-envs': JSON.stringify(mergedClientEnvs), }, body: JSON.stringify({ - project_name: "writer", + project_name: 'writer', code, intent, client_opts: {}, @@ -145,12 +172,18 @@ const remoteStainlessHandler = async ( if (!res.ok) { if (res.status === 404 && !reqContext.stainlessApiKey) { - throw new Error('Could not access code tool for this project. You may need to provide a Stainless API key via the STAINLESS_API_KEY environment variable, the --stainless-api-key flag, or the x-stainless-api-key HTTP header.'); + throw new Error( + 'Could not access code tool for this project. You may need to provide a Stainless API key via the STAINLESS_API_KEY environment variable, the --stainless-api-key flag, or the x-stainless-api-key HTTP header.', + ); } - throw new Error(`${res.status}: ${res.statusText} error when trying to contact Code Tool server. Details: ${await res.text()}`); + throw new Error( + `${res.status}: ${ + res.statusText + } error when trying to contact Code Tool server. Details: ${await res.text()}`, + ); } - const { is_error, result, log_lines, err_lines } = await res.json() as WorkerOutput; + const { is_error, result, log_lines, err_lines } = (await res.json()) as WorkerOutput; const hasLogs = log_lines.length > 0 || err_lines.length > 0; const output = { result, @@ -158,17 +191,18 @@ const remoteStainlessHandler = async ( ...(err_lines.length > 0 && { err_lines }), }; if (is_error) { - return asErrorResult( - typeof result === 'string' && !hasLogs ? result : JSON.stringify(output, null, 2), - ); + return asErrorResult(typeof result === 'string' && !hasLogs ? result : JSON.stringify(output, null, 2)); } return asTextContentResult(output); }; -const localDenoHandler = async ( - {reqContext, args} : - {reqContext: McpRequestContext, args: unknown}, -): Promise => { +const localDenoHandler = async ({ + reqContext, + args, +}: { + reqContext: McpRequestContext; + args: unknown; +}): Promise => { const fs = await import('node:fs'); const path = await import('node:path'); const url = await import('node:url'); @@ -193,24 +227,20 @@ const localDenoHandler = async ( } catch { try { // Use deno binary in node_modules if it's found - const denoNodeModulesPath = path.resolve( - packageNodeModulesPath, - 'deno', - 'bin.cjs', - ); + const denoNodeModulesPath = path.resolve(packageNodeModulesPath, 'deno', 'bin.cjs'); await fs.promises.access(denoNodeModulesPath, fs.constants.X_OK); denoPath = denoNodeModulesPath; } catch { return asErrorResult( 'Deno is required for code execution but was not found. ' + - 'Install it from https://deno.land or run: npm install deno', + 'Install it from https://deno.land or run: npm install deno', ); } } const allowReadPaths = [ 'code-tool-worker.mjs', - `${workerPath.replace(/([\/\\]node_modules)[\/\\].+$/, "$1")}/`, + `${workerPath.replace(/([\/\\]node_modules)[\/\\].+$/, '$1')}/`, packageRoot, ]; @@ -244,7 +274,7 @@ const localDenoHandler = async ( // Merge any upstream client envs into the Deno subprocess environment, // with the upstream env vars taking precedence. env: { ...process.env, ...reqContext.upstreamClientEnvs }, - } + }, }); try { @@ -256,11 +286,11 @@ const localDenoHandler = async ( // Strip null/undefined values so that the worker SDK client can fall back to // reading from environment variables (including any upstreamClientEnvs). const opts = { - ...(client.baseURL != null ? { baseURL: client.baseURL } : undefined), - ...(client.apiKey != null ? { apiKey: client.apiKey } : undefined), - defaultHeaders: { - 'X-Stainless-MCP': 'true', - }, + ...(client.baseURL != null ? { baseURL: client.baseURL } : undefined), + ...(client.apiKey != null ? { apiKey: client.apiKey } : undefined), + defaultHeaders: { + 'X-Stainless-MCP': 'true', + }, } satisfies Partial as ClientOptions; const req = worker.request( @@ -307,11 +337,12 @@ const localDenoHandler = async ( if (resp.status === 200) { const { result, log_lines, err_lines } = (await resp.json()) as WorkerOutput; const returnOutput: ContentBlock | null = - result == null ? null - : { + result == null ? null : ( + { type: 'text', text: typeof result === 'string' ? result : JSON.stringify(result), - }; + } + ); const logOutput: ContentBlock | null = log_lines.length === 0 ? null @@ -332,11 +363,12 @@ const localDenoHandler = async ( } else { const { result, log_lines, err_lines } = (await resp.json()) as WorkerOutput; const messageOutput: ContentBlock | null = - result == null ? null - : { + result == null ? null : ( + { type: 'text', text: typeof result === 'string' ? result : JSON.stringify(result), - }; + } + ); const logOutput: ContentBlock | null = log_lines.length === 0 ? null diff --git a/packages/mcp-server/src/docs-search-tool.ts b/packages/mcp-server/src/docs-search-tool.ts index 81f052dc..fb36ce2c 100644 --- a/packages/mcp-server/src/docs-search-tool.ts +++ b/packages/mcp-server/src/docs-search-tool.ts @@ -14,7 +14,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'search_docs', - description: 'Search SDK documentation to find methods, parameters, and usage examples for interacting with the API. Use this before writing code when you need to discover the right approach.', + description: + 'Search SDK documentation to find methods, parameters, and usage examples for interacting with the API. Use this before writing code when you need to discover the right approach.', inputSchema: { type: 'object', properties: { @@ -31,7 +32,7 @@ export const tool: Tool = { type: 'string', description: 'The amount of detail to return.', enum: ['default', 'verbose'], - } + }, }, required: ['query', 'language'], }, @@ -40,7 +41,8 @@ export const tool: Tool = { }, }; -const docsSearchURL = process.env['DOCS_SEARCH_URL'] || 'https://api.stainless.com/api/projects/writer/docs/search' +const docsSearchURL = + process.env['DOCS_SEARCH_URL'] || 'https://api.stainless.com/api/projects/writer/docs/search'; let _localSearch: LocalDocsSearch | undefined; @@ -65,30 +67,27 @@ async function searchLocal(args: Record): Promise { }).results; } -async function searchRemote( - args: Record, - reqContext: McpRequestContext, -): Promise { +async function searchRemote(args: Record, reqContext: McpRequestContext): Promise { const body = args as any; const query = new URLSearchParams(body).toString(); const startTime = Date.now(); - const result = await fetch( - `${docsSearchURL}?${query}`, - { - headers: { - ...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey }), - ...(reqContext.mcpSessionId && { 'x-stainless-mcp-session-id': reqContext.mcpSessionId }), - ...(reqContext.mcpClientInfo && { 'x-stainless-mcp-client-info': JSON.stringify(reqContext.mcpClientInfo) }), - }, + const result = await fetch(`${docsSearchURL}?${query}`, { + headers: { + ...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey }), + ...(reqContext.mcpSessionId && { 'x-stainless-mcp-session-id': reqContext.mcpSessionId }), + ...(reqContext.mcpClientInfo && { + 'x-stainless-mcp-client-info': JSON.stringify(reqContext.mcpClientInfo), + }), }, - ); + }); const logger = getLogger(); if (!result.ok) { const errorText = await result.text(); - logger.warn({ + logger.warn( + { durationMs: Date.now() - startTime, query: body.query, status: result.status, @@ -99,14 +98,19 @@ async function searchRemote( ); if (result.status === 404 && !reqContext.stainlessApiKey) { - throw new Error('Could not find docs for this project. You may need to provide a Stainless API key via the STAINLESS_API_KEY environment variable, the --stainless-api-key flag, or the x-stainless-api-key HTTP header.'); + throw new Error( + 'Could not find docs for this project. You may need to provide a Stainless API key via the STAINLESS_API_KEY environment variable, the --stainless-api-key flag, or the x-stainless-api-key HTTP header.', + ); } - throw new Error(`${result.status}: ${result.statusText} when using doc search tool. Details: ${errorText}`); + throw new Error( + `${result.status}: ${result.statusText} when using doc search tool. Details: ${errorText}`, + ); } const resultBody = await result.json(); - logger.info({ + logger.info( + { durationMs: Date.now() - startTime, query: body.query, }, @@ -115,10 +119,13 @@ async function searchRemote( return resultBody; } -export const handler = async ( - { reqContext, args }: - { reqContext: McpRequestContext; args: Record | undefined }, -) => { +export const handler = async ({ + reqContext, + args, +}: { + reqContext: McpRequestContext; + args: Record | undefined; +}) => { const body = args ?? {}; if (_localSearch) { diff --git a/packages/mcp-server/src/http.ts b/packages/mcp-server/src/http.ts index 5a4155f6..9a5cc972 100644 --- a/packages/mcp-server/src/http.ts +++ b/packages/mcp-server/src/http.ts @@ -1,7 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; -import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js' +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import { ClientOptions } from 'writer-sdk'; import express from 'express'; import pino from 'pino'; @@ -24,7 +24,7 @@ const newServer = async ({ }): Promise => { const stainlessApiKey = getStainlessApiKey(req, mcpOptions); const customInstructionsPath = mcpOptions.customInstructionsPath; - const server = await newMcpServer({stainlessApiKey, customInstructionsPath}); + const server = await newMcpServer({ stainlessApiKey, customInstructionsPath }); const authOptions = parseClientAuthHeaders(req, false); @@ -65,15 +65,13 @@ const newServer = async ({ ); } } catch (error) { - getLogger().warn( - { error }, - 'Failed to parse x-stainless-mcp-client-permissions header', - ); + getLogger().warn({ error }, 'Failed to parse x-stainless-mcp-client-permissions header'); } } - const mcpClientInfo = typeof req.body?.params?.clientInfo?.name === 'string' - ? { name: req.body.params.clientInfo.name, version: String(req.body.params.clientInfo.version ?? '') } + const mcpClientInfo = + typeof req.body?.params?.clientInfo?.name === 'string' ? + { name: req.body.params.clientInfo.name, version: String(req.body.params.clientInfo.version ?? '') } : undefined; await initMcpServer({ @@ -90,10 +88,7 @@ const newServer = async ({ }); if (mcpClientInfo) { - getLogger().info( - { mcpSessionId: (req as any).mcpSessionId, mcpClientInfo }, - 'MCP client connected', - ); + getLogger().info({ mcpSessionId: (req as any).mcpSessionId, mcpClientInfo }, 'MCP client connected'); } return server; @@ -133,7 +128,7 @@ const del = async (req: express.Request, res: express.Response) => { const redactHeaders = (headers: Record) => { const hiddenHeaders = /auth|cookie|key|token|x-stainless-mcp-client-envs/i; const filtered = { ...headers }; - Object.keys(filtered).forEach(key => { + Object.keys(filtered).forEach((key) => { if (hiddenHeaders.test(key)) { filtered[key] = '[REDACTED]'; } @@ -186,17 +181,17 @@ export const streamableHTTPApp = ({ req: pino.stdSerializers.wrapRequestSerializer((req) => { return { ...req, - headers: redactHeaders(req.raw.headers) + headers: redactHeaders(req.raw.headers), }; }), res: pino.stdSerializers.wrapResponseSerializer((res) => { return { ...res, - headers: redactHeaders(res.headers) + headers: redactHeaders(res.headers), }; }), - } - }) + }, + }), ); app.get('/health', async (req: express.Request, res: express.Response) => { @@ -209,23 +204,24 @@ export const streamableHTTPApp = ({ return app; }; -export const launchStreamableHTTPServer = async( - {mcpOptions, port}: { - mcpOptions: McpOptions, - port: number | string | undefined, - } -) => { - const app = streamableHTTPApp({ mcpOptions }); - const server = app.listen(port); - const address = server.address(); - - const logger = getLogger(); - - if (typeof address === 'string') { - logger.info(`MCP Server running on streamable HTTP at ${address}`); - } else if (address !== null) { - logger.info(`MCP Server running on streamable HTTP on port ${address.port}`); - } else { - logger.info(`MCP Server running on streamable HTTP on port ${port}`); - } +export const launchStreamableHTTPServer = async ({ + mcpOptions, + port, +}: { + mcpOptions: McpOptions; + port: number | string | undefined; +}) => { + const app = streamableHTTPApp({ mcpOptions }); + const server = app.listen(port); + const address = server.address(); + + const logger = getLogger(); + + if (typeof address === 'string') { + logger.info(`MCP Server running on streamable HTTP at ${address}`); + } else if (address !== null) { + logger.info(`MCP Server running on streamable HTTP on port ${address.port}`); + } else { + logger.info(`MCP Server running on streamable HTTP on port ${port}`); } +}; diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index 6306dc26..5bca4a60 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -17,7 +17,7 @@ async function main() { const selectedTools = await selectToolsOrError(options); getLogger().info( - {tools: selectedTools.map((e) => e.tool.name)}, + { tools: selectedTools.map((e) => e.tool.name) }, `MCP Server starting with ${selectedTools.length} tools`, ); diff --git a/packages/mcp-server/src/instructions.ts b/packages/mcp-server/src/instructions.ts index 10714a28..8c70804c 100644 --- a/packages/mcp-server/src/instructions.ts +++ b/packages/mcp-server/src/instructions.ts @@ -60,24 +60,24 @@ async function fetchLatestInstructionsFromApi(stainlessApiKey: string | undefine // Setting the stainless API key is optional, but may be required // to authenticate requests to the Stainless API. const response = await fetch( - readEnv("CODE_MODE_INSTRUCTIONS_URL") ?? - 'https://api.stainless.com/api/ai/instructions/writer', + readEnv('CODE_MODE_INSTRUCTIONS_URL') ?? 'https://api.stainless.com/api/ai/instructions/writer', { - method: "GET", - headers: { ...( stainlessApiKey && { Authorization: stainlessApiKey } ) } - } - ) + method: 'GET', + headers: { ...(stainlessApiKey && { Authorization: stainlessApiKey }) }, + }, + ); let instructions: string | undefined; if (!response.ok) { getLogger().warn( - "Warning: failed to retrieve MCP server instructions. Proceeding with default instructions..." - ) + 'Warning: failed to retrieve MCP server instructions. Proceeding with default instructions...', + ); - instructions = "\n This is the writer MCP server.\n\n Available tools:\n - search_docs: Search SDK documentation to find the right methods and parameters.\n - execute: Run TypeScript code against a pre-authenticated SDK client. Define an async run(client) function.\n\n Workflow:\n - If unsure about the API, call search_docs first.\n - Write complete solutions in a single execute call when possible. For large datasets, use API filters to narrow results or paginate within a single execute block.\n - If execute returns an error, read the error and fix your code rather than retrying the same approach.\n - Variables do not persist between execute calls. Return or log all data you need.\n - Individual HTTP requests to the API have a 30-second timeout. If a request times out, try a smaller query or add filters.\n - Code execution has a total timeout of approximately 5 minutes. If your code times out, simplify it or break it into smaller steps.\n "; + instructions = + '\n This is the writer MCP server.\n\n Available tools:\n - search_docs: Search SDK documentation to find the right methods and parameters.\n - execute: Run TypeScript code against a pre-authenticated SDK client. Define an async run(client) function.\n\n Workflow:\n - If unsure about the API, call search_docs first.\n - Write complete solutions in a single execute call when possible. For large datasets, use API filters to narrow results or paginate within a single execute block.\n - If execute returns an error, read the error and fix your code rather than retrying the same approach.\n - Variables do not persist between execute calls. Return or log all data you need.\n - Individual HTTP requests to the API have a 30-second timeout. If a request times out, try a smaller query or add filters.\n - Code execution has a total timeout of approximately 5 minutes. If your code times out, simplify it or break it into smaller steps.\n '; } - instructions ??= (await response.json() as { instructions: string }).instructions; + instructions ??= ((await response.json()) as { instructions: string }).instructions; return instructions; } diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index db78996e..f90a9750 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -51,1020 +51,1145 @@ type SearchResult = { const EMBEDDED_METHODS: MethodEntry[] = [ { - "name": "generate_content", - "endpoint": "/v1/applications/{application_id}", - "httpMethod": "post", - "summary": "Generate from application", - "description": "Generate content from an existing no-code agent (formerly called no-code applications) with inputs.", - "stainlessPath": "(resource) applications > (method) generate_content", - "qualified": "client.applications.generateContent", - "params": [ - "application_id: string;", - "inputs: { id: string; value: string[]; }[];", - "stream?: boolean;" - ], - "response": "{ suggestion: string; title?: string; }", - "markdown": "## generate_content\n\n`client.applications.generateContent(application_id: string, inputs: { id: string; value: string[]; }[], stream?: boolean): { suggestion: string; title?: string; }`\n\n**post** `/v1/applications/{application_id}`\n\nGenerate content from an existing no-code agent (formerly called no-code applications) with inputs.\n\n### Parameters\n\n- `application_id: string`\n\n- `inputs: { id: string; value: string[]; }[]`\n\n- `stream?: boolean`\n Indicates whether the response should be streamed. Currently only supported for research assistant applications.\n\n### Returns\n\n- `{ suggestion: string; title?: string; }`\n\n - `suggestion: string`\n - `title?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.applications.generateContent('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { inputs: [{ id: 'id', value: ['string'] }] });\nfor await (const applicationGenerateContentChunk of stream) {\n console.log(applicationGenerateContentChunk);\n}\n```", - "perLanguage": { - "typescript": { - "method": "client.applications.generateContent", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGenerateContentResponse = await client.applications.generateContent(\n '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n { inputs: [{ id: 'id', value: ['string'] }] },\n);\n\nconsole.log(applicationGenerateContentResponse.suggestion);" - }, - "python": { - "method": "applications.generate_content", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfor application in client.applications.generate_content(\n application_id=\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n inputs=[{\n \"id\": \"id\",\n \"value\": [\"string\"],\n }],\n):\n print(application)" - }, - "go": { - "method": "client.Applications.GenerateContent", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tapplicationGenerateContentResponse, err := client.Applications.GenerateContent(\n\t\tcontext.TODO(),\n\t\t\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n\t\twritersdk.ApplicationGenerateContentParams{\n\t\t\tInputs: writersdk.F([]writersdk.ApplicationGenerateContentParamsInput{{\n\t\t\t\tID: writersdk.F(\"id\"),\n\t\t\t\tValue: writersdk.F([]string{\"string\"}),\n\t\t\t}}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", applicationGenerateContentResponse.Suggestion)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/applications/$APPLICATION_ID \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"inputs\": [\n {\n \"id\": \"id\",\n \"value\": [\n \"string\"\n ]\n }\n ]\n }'" - } - } + name: 'generate_content', + endpoint: '/v1/applications/{application_id}', + httpMethod: 'post', + summary: 'Generate from application', + description: + 'Generate content from an existing no-code agent (formerly called no-code applications) with inputs.', + stainlessPath: '(resource) applications > (method) generate_content', + qualified: 'client.applications.generateContent', + params: ['application_id: string;', 'inputs: { id: string; value: string[]; }[];', 'stream?: boolean;'], + response: '{ suggestion: string; title?: string; }', + markdown: + "## generate_content\n\n`client.applications.generateContent(application_id: string, inputs: { id: string; value: string[]; }[], stream?: boolean): { suggestion: string; title?: string; }`\n\n**post** `/v1/applications/{application_id}`\n\nGenerate content from an existing no-code agent (formerly called no-code applications) with inputs.\n\n### Parameters\n\n- `application_id: string`\n\n- `inputs: { id: string; value: string[]; }[]`\n\n- `stream?: boolean`\n Indicates whether the response should be streamed. Currently only supported for research assistant applications.\n\n### Returns\n\n- `{ suggestion: string; title?: string; }`\n\n - `suggestion: string`\n - `title?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.applications.generateContent('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { inputs: [{ id: 'id', value: ['string'] }] });\nfor await (const applicationGenerateContentChunk of stream) {\n console.log(applicationGenerateContentChunk);\n}\n```", + perLanguage: { + typescript: { + method: 'client.applications.generateContent', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGenerateContentResponse = await client.applications.generateContent(\n '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n { inputs: [{ id: 'id', value: ['string'] }] },\n);\n\nconsole.log(applicationGenerateContentResponse.suggestion);", + }, + python: { + method: 'applications.generate_content', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfor application in client.applications.generate_content(\n application_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n inputs=[{\n "id": "id",\n "value": ["string"],\n }],\n):\n print(application)', + }, + go: { + method: 'client.Applications.GenerateContent', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGenerateContentResponse, err := client.Applications.GenerateContent(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\twritersdk.ApplicationGenerateContentParams{\n\t\t\tInputs: writersdk.F([]writersdk.ApplicationGenerateContentParamsInput{{\n\t\t\t\tID: writersdk.F("id"),\n\t\t\t\tValue: writersdk.F([]string{"string"}),\n\t\t\t}}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGenerateContentResponse.Suggestion)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/$APPLICATION_ID \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "inputs": [\n {\n "id": "id",\n "value": [\n "string"\n ]\n }\n ]\n }\'', + }, + }, }, { - "name": "list", - "endpoint": "/v1/applications", - "httpMethod": "get", - "summary": "List applications", - "description": "Retrieves a paginated list of no-code agents (formerly called no-code applications) with optional filtering and sorting capabilities.", - "stainlessPath": "(resource) applications > (method) list", - "qualified": "client.applications.list", - "params": [ - "after?: string;", - "before?: string;", - "limit?: number;", + name: 'list', + endpoint: '/v1/applications', + httpMethod: 'get', + summary: 'List applications', + description: + 'Retrieves a paginated list of no-code agents (formerly called no-code applications) with optional filtering and sorting capabilities.', + stainlessPath: '(resource) applications > (method) list', + qualified: 'client.applications.list', + params: [ + 'after?: string;', + 'before?: string;', + 'limit?: number;', "order?: 'asc' | 'desc';", - "type?: 'generation';" + "type?: 'generation';", ], - "response": "{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }", - "markdown": "## list\n\n`client.applications.list(after?: string, before?: string, limit?: number, order?: 'asc' | 'desc', type?: 'generation'): { id: string; created_at: string; inputs: object[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n\n**get** `/v1/applications`\n\nRetrieves a paginated list of no-code agents (formerly called no-code applications) with optional filtering and sorting capabilities.\n\n### Parameters\n\n- `after?: string`\n Return results after this application ID for pagination.\n\n- `before?: string`\n Return results before this application ID for pagination.\n\n- `limit?: number`\n Maximum number of applications to return in the response.\n\n- `order?: 'asc' | 'desc'`\n Sort order for the results based on creation time.\n\n- `type?: 'generation'`\n Filter applications by their type.\n\n### Returns\n\n- `{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n Detailed application object including its input configuration.\n\n - `id: string`\n - `created_at: string`\n - `inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]`\n - `name: string`\n - `status: 'deployed' | 'draft'`\n - `type: 'generation'`\n - `updated_at: string`\n - `last_deployed_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const applicationListResponse of client.applications.list()) {\n console.log(applicationListResponse);\n}\n```", - "perLanguage": { - "typescript": { - "method": "client.applications.list", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const applicationListResponse of client.applications.list()) {\n console.log(applicationListResponse.id);\n}" - }, - "python": { - "method": "applications.list", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\npage = client.applications.list()\npage = page.data[0]\nprint(page.id)" - }, - "go": { - "method": "client.Applications.List", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tpage, err := client.Applications.List(context.TODO(), writersdk.ApplicationListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", page)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/applications \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + response: + "{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }", + markdown: + "## list\n\n`client.applications.list(after?: string, before?: string, limit?: number, order?: 'asc' | 'desc', type?: 'generation'): { id: string; created_at: string; inputs: object[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n\n**get** `/v1/applications`\n\nRetrieves a paginated list of no-code agents (formerly called no-code applications) with optional filtering and sorting capabilities.\n\n### Parameters\n\n- `after?: string`\n Return results after this application ID for pagination.\n\n- `before?: string`\n Return results before this application ID for pagination.\n\n- `limit?: number`\n Maximum number of applications to return in the response.\n\n- `order?: 'asc' | 'desc'`\n Sort order for the results based on creation time.\n\n- `type?: 'generation'`\n Filter applications by their type.\n\n### Returns\n\n- `{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n Detailed application object including its input configuration.\n\n - `id: string`\n - `created_at: string`\n - `inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]`\n - `name: string`\n - `status: 'deployed' | 'draft'`\n - `type: 'generation'`\n - `updated_at: string`\n - `last_deployed_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const applicationListResponse of client.applications.list()) {\n console.log(applicationListResponse);\n}\n```", + perLanguage: { + typescript: { + method: 'client.applications.list', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const applicationListResponse of client.applications.list()) {\n console.log(applicationListResponse.id);\n}", + }, + python: { + method: 'applications.list', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\npage = client.applications.list()\npage = page.data[0]\nprint(page.id)', + }, + go: { + method: 'client.Applications.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Applications.List(context.TODO(), writersdk.ApplicationListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "retrieve", - "endpoint": "/v1/applications/{application_id}", - "httpMethod": "get", - "summary": "Application details", - "description": "Retrieves detailed information for a specific no-code agent (formerly called no-code applications), including its configuration and current status.", - "stainlessPath": "(resource) applications > (method) retrieve", - "qualified": "client.applications.retrieve", - "params": [ - "application_id: string;" - ], - "response": "{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }", - "markdown": "## retrieve\n\n`client.applications.retrieve(application_id: string): { id: string; created_at: string; inputs: object[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n\n**get** `/v1/applications/{application_id}`\n\nRetrieves detailed information for a specific no-code agent (formerly called no-code applications), including its configuration and current status.\n\n### Parameters\n\n- `application_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n Detailed application object including its input configuration.\n\n - `id: string`\n - `created_at: string`\n - `inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]`\n - `name: string`\n - `status: 'deployed' | 'draft'`\n - `type: 'generation'`\n - `updated_at: string`\n - `last_deployed_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst application = await client.applications.retrieve('application_id');\n\nconsole.log(application);\n```", - "perLanguage": { - "typescript": { - "method": "client.applications.retrieve", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst application = await client.applications.retrieve('application_id');\n\nconsole.log(application.id);" - }, - "python": { - "method": "applications.retrieve", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\napplication = client.applications.retrieve(\n \"application_id\",\n)\nprint(application.id)" - }, - "go": { - "method": "client.Applications.Get", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tapplication, err := client.Applications.Get(context.TODO(), \"application_id\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", application.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/applications/$APPLICATION_ID \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + name: 'retrieve', + endpoint: '/v1/applications/{application_id}', + httpMethod: 'get', + summary: 'Application details', + description: + 'Retrieves detailed information for a specific no-code agent (formerly called no-code applications), including its configuration and current status.', + stainlessPath: '(resource) applications > (method) retrieve', + qualified: 'client.applications.retrieve', + params: ['application_id: string;'], + response: + "{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }", + markdown: + "## retrieve\n\n`client.applications.retrieve(application_id: string): { id: string; created_at: string; inputs: object[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n\n**get** `/v1/applications/{application_id}`\n\nRetrieves detailed information for a specific no-code agent (formerly called no-code applications), including its configuration and current status.\n\n### Parameters\n\n- `application_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]; name: string; status: 'deployed' | 'draft'; type: 'generation'; updated_at: string; last_deployed_at?: string; }`\n Detailed application object including its input configuration.\n\n - `id: string`\n - `created_at: string`\n - `inputs: { input_type: 'text' | 'dropdown' | 'file' | 'media'; name: string; required: boolean; description?: string; options?: { list: string[]; } | { file_types: string[]; max_file_size_mb: number; max_files: number; max_word_count: number; upload_types: 'url' | 'file_id'[]; } | { file_types: string[]; max_image_size_mb: number; } | { max_fields: number; min_fields: number; }; }[]`\n - `name: string`\n - `status: 'deployed' | 'draft'`\n - `type: 'generation'`\n - `updated_at: string`\n - `last_deployed_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst application = await client.applications.retrieve('application_id');\n\nconsole.log(application);\n```", + perLanguage: { + typescript: { + method: 'client.applications.retrieve', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst application = await client.applications.retrieve('application_id');\n\nconsole.log(application.id);", + }, + python: { + method: 'applications.retrieve', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\napplication = client.applications.retrieve(\n "application_id",\n)\nprint(application.id)', + }, + go: { + method: 'client.Applications.Get', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplication, err := client.Applications.Get(context.TODO(), "application_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", application.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/$APPLICATION_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "list", - "endpoint": "/v1/applications/{application_id}/jobs", - "httpMethod": "get", - "summary": "Retrieve all jobs", - "description": "Retrieve all jobs created via the async API, linked to the provided application ID (or alias).", - "stainlessPath": "(resource) applications.jobs > (method) list", - "qualified": "client.applications.jobs.list", - "params": [ - "application_id: string;", - "limit?: number;", - "offset?: number;", - "status?: 'in_progress' | 'failed' | 'completed';" + name: 'list', + endpoint: '/v1/applications/{application_id}/jobs', + httpMethod: 'get', + summary: 'Retrieve all jobs', + description: + 'Retrieve all jobs created via the async API, linked to the provided application ID (or alias).', + stainlessPath: '(resource) applications.jobs > (method) list', + qualified: 'client.applications.jobs.list', + params: [ + 'application_id: string;', + 'limit?: number;', + 'offset?: number;', + "status?: 'in_progress' | 'failed' | 'completed';", ], - "response": "{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }", - "markdown": "## list\n\n`client.applications.jobs.list(application_id: string, limit?: number, offset?: number, status?: 'in_progress' | 'failed' | 'completed'): { id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: application_generate_content_response; error?: string; updated_at?: string; }`\n\n**get** `/v1/applications/{application_id}/jobs`\n\nRetrieve all jobs created via the async API, linked to the provided application ID (or alias).\n\n### Parameters\n\n- `application_id: string`\n\n- `limit?: number`\n The pagination limit for retrieving the jobs.\n\n- `offset?: number`\n The pagination offset for retrieving the jobs.\n\n- `status?: 'in_progress' | 'failed' | 'completed'`\n The status of the job.\n\n### Returns\n\n- `{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }`\n\n - `id: string`\n - `application_id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n - `completed_at?: string`\n - `data?: { suggestion: string; title?: string; }`\n - `error?: string`\n - `updated_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const applicationGenerateAsyncResponse of client.applications.jobs.list('application_id')) {\n console.log(applicationGenerateAsyncResponse);\n}\n```", - "perLanguage": { - "typescript": { - "method": "client.applications.jobs.list", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const applicationGenerateAsyncResponse of client.applications.jobs.list(\n 'application_id',\n)) {\n console.log(applicationGenerateAsyncResponse.id);\n}" - }, - "python": { - "method": "applications.jobs.list", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\npage = client.applications.jobs.list(\n application_id=\"application_id\",\n)\npage = page.result[0]\nprint(page.id)" - }, - "go": { - "method": "client.Applications.Jobs.List", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tpage, err := client.Applications.Jobs.List(\n\t\tcontext.TODO(),\n\t\t\"application_id\",\n\t\twritersdk.ApplicationJobListParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", page)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/applications/$APPLICATION_ID/jobs \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + response: + "{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }", + markdown: + "## list\n\n`client.applications.jobs.list(application_id: string, limit?: number, offset?: number, status?: 'in_progress' | 'failed' | 'completed'): { id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: application_generate_content_response; error?: string; updated_at?: string; }`\n\n**get** `/v1/applications/{application_id}/jobs`\n\nRetrieve all jobs created via the async API, linked to the provided application ID (or alias).\n\n### Parameters\n\n- `application_id: string`\n\n- `limit?: number`\n The pagination limit for retrieving the jobs.\n\n- `offset?: number`\n The pagination offset for retrieving the jobs.\n\n- `status?: 'in_progress' | 'failed' | 'completed'`\n The status of the job.\n\n### Returns\n\n- `{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }`\n\n - `id: string`\n - `application_id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n - `completed_at?: string`\n - `data?: { suggestion: string; title?: string; }`\n - `error?: string`\n - `updated_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const applicationGenerateAsyncResponse of client.applications.jobs.list('application_id')) {\n console.log(applicationGenerateAsyncResponse);\n}\n```", + perLanguage: { + typescript: { + method: 'client.applications.jobs.list', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const applicationGenerateAsyncResponse of client.applications.jobs.list(\n 'application_id',\n)) {\n console.log(applicationGenerateAsyncResponse.id);\n}", + }, + python: { + method: 'applications.jobs.list', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\npage = client.applications.jobs.list(\n application_id="application_id",\n)\npage = page.result[0]\nprint(page.id)', + }, + go: { + method: 'client.Applications.Jobs.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Applications.Jobs.List(\n\t\tcontext.TODO(),\n\t\t"application_id",\n\t\twritersdk.ApplicationJobListParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/jobs \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "create", - "endpoint": "/v1/applications/{application_id}/jobs", - "httpMethod": "post", - "summary": "Generate from application (async)", - "description": "Generate content asynchronously from an existing no-code agent (formerly called no-code applications) with inputs.", - "stainlessPath": "(resource) applications.jobs > (method) create", - "qualified": "client.applications.jobs.create", - "params": [ - "application_id: string;", - "inputs: { id: string; value: string[]; }[];" - ], - "response": "{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }", - "markdown": "## create\n\n`client.applications.jobs.create(application_id: string, inputs: { id: string; value: string[]; }[]): { id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n**post** `/v1/applications/{application_id}/jobs`\n\nGenerate content asynchronously from an existing no-code agent (formerly called no-code applications) with inputs.\n\n### Parameters\n\n- `application_id: string`\n\n- `inputs: { id: string; value: string[]; }[]`\n A list of input objects to generate content for.\n\n### Returns\n\n- `{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n - `id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst job = await client.applications.jobs.create('application_id', { inputs: [{ id: 'id', value: ['string'] }] });\n\nconsole.log(job);\n```", - "perLanguage": { - "typescript": { - "method": "client.applications.jobs.create", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst job = await client.applications.jobs.create('application_id', {\n inputs: [{ id: 'id', value: ['string'] }],\n});\n\nconsole.log(job.id);" - }, - "python": { - "method": "applications.jobs.create", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\njob = client.applications.jobs.create(\n application_id=\"application_id\",\n inputs=[{\n \"id\": \"id\",\n \"value\": [\"string\"],\n }],\n)\nprint(job.id)" - }, - "go": { - "method": "client.Applications.Jobs.New", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tjob, err := client.Applications.Jobs.New(\n\t\tcontext.TODO(),\n\t\t\"application_id\",\n\t\twritersdk.ApplicationJobNewParams{\n\t\t\tInputs: writersdk.F([]writersdk.ApplicationJobNewParamsInput{{\n\t\t\t\tID: writersdk.F(\"id\"),\n\t\t\t\tValue: writersdk.F([]string{\"string\"}),\n\t\t\t}}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", job.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/applications/$APPLICATION_ID/jobs \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"inputs\": [\n {\n \"id\": \"id\",\n \"value\": [\n \"string\"\n ]\n }\n ]\n }'" - } - } + name: 'create', + endpoint: '/v1/applications/{application_id}/jobs', + httpMethod: 'post', + summary: 'Generate from application (async)', + description: + 'Generate content asynchronously from an existing no-code agent (formerly called no-code applications) with inputs.', + stainlessPath: '(resource) applications.jobs > (method) create', + qualified: 'client.applications.jobs.create', + params: ['application_id: string;', 'inputs: { id: string; value: string[]; }[];'], + response: "{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }", + markdown: + "## create\n\n`client.applications.jobs.create(application_id: string, inputs: { id: string; value: string[]; }[]): { id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n**post** `/v1/applications/{application_id}/jobs`\n\nGenerate content asynchronously from an existing no-code agent (formerly called no-code applications) with inputs.\n\n### Parameters\n\n- `application_id: string`\n\n- `inputs: { id: string; value: string[]; }[]`\n A list of input objects to generate content for.\n\n### Returns\n\n- `{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n - `id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst job = await client.applications.jobs.create('application_id', { inputs: [{ id: 'id', value: ['string'] }] });\n\nconsole.log(job);\n```", + perLanguage: { + typescript: { + method: 'client.applications.jobs.create', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst job = await client.applications.jobs.create('application_id', {\n inputs: [{ id: 'id', value: ['string'] }],\n});\n\nconsole.log(job.id);", + }, + python: { + method: 'applications.jobs.create', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\njob = client.applications.jobs.create(\n application_id="application_id",\n inputs=[{\n "id": "id",\n "value": ["string"],\n }],\n)\nprint(job.id)', + }, + go: { + method: 'client.Applications.Jobs.New', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tjob, err := client.Applications.Jobs.New(\n\t\tcontext.TODO(),\n\t\t"application_id",\n\t\twritersdk.ApplicationJobNewParams{\n\t\t\tInputs: writersdk.F([]writersdk.ApplicationJobNewParamsInput{{\n\t\t\t\tID: writersdk.F("id"),\n\t\t\t\tValue: writersdk.F([]string{"string"}),\n\t\t\t}}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", job.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/jobs \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "inputs": [\n {\n "id": "id",\n "value": [\n "string"\n ]\n }\n ]\n }\'', + }, + }, }, { - "name": "retry", - "endpoint": "/v1/applications/jobs/{job_id}/retry", - "httpMethod": "post", - "summary": "Retry job execution", - "description": "Re-triggers the async execution of a single job previously created via the Async api and terminated in error.", - "stainlessPath": "(resource) applications.jobs > (method) retry", - "qualified": "client.applications.jobs.retry", - "params": [ - "job_id: string;" - ], - "response": "{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }", - "markdown": "## retry\n\n`client.applications.jobs.retry(job_id: string): { id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n**post** `/v1/applications/jobs/{job_id}/retry`\n\nRe-triggers the async execution of a single job previously created via the Async api and terminated in error.\n\n### Parameters\n\n- `job_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n - `id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.applications.jobs.retry('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(response);\n```", - "perLanguage": { - "typescript": { - "method": "client.applications.jobs.retry", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.applications.jobs.retry('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(response.id);" - }, - "python": { - "method": "applications.jobs.retry", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nresponse = client.applications.jobs.retry(\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n)\nprint(response.id)" - }, - "go": { - "method": "client.Applications.Jobs.Retry", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tresponse, err := client.Applications.Jobs.Retry(context.TODO(), \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", response.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/applications/jobs/$JOB_ID/retry \\\n -X POST \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + name: 'retry', + endpoint: '/v1/applications/jobs/{job_id}/retry', + httpMethod: 'post', + summary: 'Retry job execution', + description: + 'Re-triggers the async execution of a single job previously created via the Async api and terminated in error.', + stainlessPath: '(resource) applications.jobs > (method) retry', + qualified: 'client.applications.jobs.retry', + params: ['job_id: string;'], + response: "{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }", + markdown: + "## retry\n\n`client.applications.jobs.retry(job_id: string): { id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n**post** `/v1/applications/jobs/{job_id}/retry`\n\nRe-triggers the async execution of a single job previously created via the Async api and terminated in error.\n\n### Parameters\n\n- `job_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; }`\n\n - `id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.applications.jobs.retry('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.applications.jobs.retry', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.applications.jobs.retry('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(response.id);", + }, + python: { + method: 'applications.jobs.retry', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.applications.jobs.retry(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(response.id)', + }, + go: { + method: 'client.Applications.Jobs.Retry', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Applications.Jobs.Retry(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/jobs/$JOB_ID/retry \\\n -X POST \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "retrieve", - "endpoint": "/v1/applications/jobs/{job_id}", - "httpMethod": "get", - "summary": "Retrieve a single job", - "description": "Retrieves a single job created via the Async API.", - "stainlessPath": "(resource) applications.jobs > (method) retrieve", - "qualified": "client.applications.jobs.retrieve", - "params": [ - "job_id: string;" - ], - "response": "{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }", - "markdown": "## retrieve\n\n`client.applications.jobs.retrieve(job_id: string): { id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: application_generate_content_response; error?: string; updated_at?: string; }`\n\n**get** `/v1/applications/jobs/{job_id}`\n\nRetrieves a single job created via the Async API.\n\n### Parameters\n\n- `job_id: string`\n\n### Returns\n\n- `{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }`\n\n - `id: string`\n - `application_id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n - `completed_at?: string`\n - `data?: { suggestion: string; title?: string; }`\n - `error?: string`\n - `updated_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGenerateAsyncResponse = await client.applications.jobs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(applicationGenerateAsyncResponse);\n```", - "perLanguage": { - "typescript": { - "method": "client.applications.jobs.retrieve", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGenerateAsyncResponse = await client.applications.jobs.retrieve(\n '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n);\n\nconsole.log(applicationGenerateAsyncResponse.id);" - }, - "python": { - "method": "applications.jobs.retrieve", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\napplication_generate_async_response = client.applications.jobs.retrieve(\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n)\nprint(application_generate_async_response.id)" - }, - "go": { - "method": "client.Applications.Jobs.Get", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tapplicationGenerateAsyncResponse, err := client.Applications.Jobs.Get(context.TODO(), \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", applicationGenerateAsyncResponse.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/applications/jobs/$JOB_ID \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + name: 'retrieve', + endpoint: '/v1/applications/jobs/{job_id}', + httpMethod: 'get', + summary: 'Retrieve a single job', + description: 'Retrieves a single job created via the Async API.', + stainlessPath: '(resource) applications.jobs > (method) retrieve', + qualified: 'client.applications.jobs.retrieve', + params: ['job_id: string;'], + response: + "{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }", + markdown: + "## retrieve\n\n`client.applications.jobs.retrieve(job_id: string): { id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: application_generate_content_response; error?: string; updated_at?: string; }`\n\n**get** `/v1/applications/jobs/{job_id}`\n\nRetrieves a single job created via the Async API.\n\n### Parameters\n\n- `job_id: string`\n\n### Returns\n\n- `{ id: string; application_id: string; created_at: string; status: 'in_progress' | 'failed' | 'completed'; completed_at?: string; data?: { suggestion: string; title?: string; }; error?: string; updated_at?: string; }`\n\n - `id: string`\n - `application_id: string`\n - `created_at: string`\n - `status: 'in_progress' | 'failed' | 'completed'`\n - `completed_at?: string`\n - `data?: { suggestion: string; title?: string; }`\n - `error?: string`\n - `updated_at?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGenerateAsyncResponse = await client.applications.jobs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(applicationGenerateAsyncResponse);\n```", + perLanguage: { + typescript: { + method: 'client.applications.jobs.retrieve', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGenerateAsyncResponse = await client.applications.jobs.retrieve(\n '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n);\n\nconsole.log(applicationGenerateAsyncResponse.id);", + }, + python: { + method: 'applications.jobs.retrieve', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\napplication_generate_async_response = client.applications.jobs.retrieve(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(application_generate_async_response.id)', + }, + go: { + method: 'client.Applications.Jobs.Get', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGenerateAsyncResponse, err := client.Applications.Jobs.Get(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGenerateAsyncResponse.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/jobs/$JOB_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "list", - "endpoint": "/v1/applications/{application_id}/graphs", - "httpMethod": "get", - "summary": "Retrieve graphs", - "description": "Retrieve Knowledge Graphs associated with a no-code agent that has chat capabilities.", - "stainlessPath": "(resource) applications.graphs > (method) list", - "qualified": "client.applications.graphs.list", - "params": [ - "application_id: string;" - ], - "response": "{ graph_ids: string[]; }", - "markdown": "## list\n\n`client.applications.graphs.list(application_id: string): { graph_ids: string[]; }`\n\n**get** `/v1/applications/{application_id}/graphs`\n\nRetrieve Knowledge Graphs associated with a no-code agent that has chat capabilities.\n\n### Parameters\n\n- `application_id: string`\n\n### Returns\n\n- `{ graph_ids: string[]; }`\n\n - `graph_ids: string[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGraphsResponse = await client.applications.graphs.list('application_id');\n\nconsole.log(applicationGraphsResponse);\n```", - "perLanguage": { - "typescript": { - "method": "client.applications.graphs.list", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGraphsResponse = await client.applications.graphs.list('application_id');\n\nconsole.log(applicationGraphsResponse.graph_ids);" - }, - "python": { - "method": "applications.graphs.list", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\napplication_graphs_response = client.applications.graphs.list(\n \"application_id\",\n)\nprint(application_graphs_response.graph_ids)" - }, - "go": { - "method": "client.Applications.Graphs.List", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tapplicationGraphsResponse, err := client.Applications.Graphs.List(context.TODO(), \"application_id\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", applicationGraphsResponse.GraphIDs)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/applications/$APPLICATION_ID/graphs \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + name: 'list', + endpoint: '/v1/applications/{application_id}/graphs', + httpMethod: 'get', + summary: 'Retrieve graphs', + description: 'Retrieve Knowledge Graphs associated with a no-code agent that has chat capabilities.', + stainlessPath: '(resource) applications.graphs > (method) list', + qualified: 'client.applications.graphs.list', + params: ['application_id: string;'], + response: '{ graph_ids: string[]; }', + markdown: + "## list\n\n`client.applications.graphs.list(application_id: string): { graph_ids: string[]; }`\n\n**get** `/v1/applications/{application_id}/graphs`\n\nRetrieve Knowledge Graphs associated with a no-code agent that has chat capabilities.\n\n### Parameters\n\n- `application_id: string`\n\n### Returns\n\n- `{ graph_ids: string[]; }`\n\n - `graph_ids: string[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGraphsResponse = await client.applications.graphs.list('application_id');\n\nconsole.log(applicationGraphsResponse);\n```", + perLanguage: { + typescript: { + method: 'client.applications.graphs.list', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGraphsResponse = await client.applications.graphs.list('application_id');\n\nconsole.log(applicationGraphsResponse.graph_ids);", + }, + python: { + method: 'applications.graphs.list', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\napplication_graphs_response = client.applications.graphs.list(\n "application_id",\n)\nprint(application_graphs_response.graph_ids)', + }, + go: { + method: 'client.Applications.Graphs.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGraphsResponse, err := client.Applications.Graphs.List(context.TODO(), "application_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGraphsResponse.GraphIDs)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/graphs \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "update", - "endpoint": "/v1/applications/{application_id}/graphs", - "httpMethod": "put", - "summary": "Associate graphs", - "description": "Updates the list of Knowledge Graphs associated with a no-code chat agent.", - "stainlessPath": "(resource) applications.graphs > (method) update", - "qualified": "client.applications.graphs.update", - "params": [ - "application_id: string;", - "graph_ids: string[];" - ], - "response": "{ graph_ids: string[]; }", - "markdown": "## update\n\n`client.applications.graphs.update(application_id: string, graph_ids: string[]): { graph_ids: string[]; }`\n\n**put** `/v1/applications/{application_id}/graphs`\n\nUpdates the list of Knowledge Graphs associated with a no-code chat agent.\n\n### Parameters\n\n- `application_id: string`\n\n- `graph_ids: string[]`\n A list of Knowledge Graph IDs to associate with the application. Note that this will replace the existing list of Knowledge Graphs associated with the application, not add to it.\n\n### Returns\n\n- `{ graph_ids: string[]; }`\n\n - `graph_ids: string[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGraphsResponse = await client.applications.graphs.update('application_id', { graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(applicationGraphsResponse);\n```", - "perLanguage": { - "typescript": { - "method": "client.applications.graphs.update", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGraphsResponse = await client.applications.graphs.update('application_id', {\n graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'],\n});\n\nconsole.log(applicationGraphsResponse.graph_ids);" - }, - "python": { - "method": "applications.graphs.update", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\napplication_graphs_response = client.applications.graphs.update(\n application_id=\"application_id\",\n graph_ids=[\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"],\n)\nprint(application_graphs_response.graph_ids)" - }, - "go": { - "method": "client.Applications.Graphs.Update", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tapplicationGraphsResponse, err := client.Applications.Graphs.Update(\n\t\tcontext.TODO(),\n\t\t\"application_id\",\n\t\twritersdk.ApplicationGraphUpdateParams{\n\t\t\tGraphIDs: writersdk.F([]string{\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", applicationGraphsResponse.GraphIDs)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/applications/$APPLICATION_ID/graphs \\\n -X PUT \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"graph_ids\": [\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"\n ]\n }'" - } - } + name: 'update', + endpoint: '/v1/applications/{application_id}/graphs', + httpMethod: 'put', + summary: 'Associate graphs', + description: 'Updates the list of Knowledge Graphs associated with a no-code chat agent.', + stainlessPath: '(resource) applications.graphs > (method) update', + qualified: 'client.applications.graphs.update', + params: ['application_id: string;', 'graph_ids: string[];'], + response: '{ graph_ids: string[]; }', + markdown: + "## update\n\n`client.applications.graphs.update(application_id: string, graph_ids: string[]): { graph_ids: string[]; }`\n\n**put** `/v1/applications/{application_id}/graphs`\n\nUpdates the list of Knowledge Graphs associated with a no-code chat agent.\n\n### Parameters\n\n- `application_id: string`\n\n- `graph_ids: string[]`\n A list of Knowledge Graph IDs to associate with the application. Note that this will replace the existing list of Knowledge Graphs associated with the application, not add to it.\n\n### Returns\n\n- `{ graph_ids: string[]; }`\n\n - `graph_ids: string[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst applicationGraphsResponse = await client.applications.graphs.update('application_id', { graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(applicationGraphsResponse);\n```", + perLanguage: { + typescript: { + method: 'client.applications.graphs.update', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst applicationGraphsResponse = await client.applications.graphs.update('application_id', {\n graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'],\n});\n\nconsole.log(applicationGraphsResponse.graph_ids);", + }, + python: { + method: 'applications.graphs.update', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\napplication_graphs_response = client.applications.graphs.update(\n application_id="application_id",\n graph_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],\n)\nprint(application_graphs_response.graph_ids)', + }, + go: { + method: 'client.Applications.Graphs.Update', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tapplicationGraphsResponse, err := client.Applications.Graphs.Update(\n\t\tcontext.TODO(),\n\t\t"application_id",\n\t\twritersdk.ApplicationGraphUpdateParams{\n\t\t\tGraphIDs: writersdk.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", applicationGraphsResponse.GraphIDs)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/applications/$APPLICATION_ID/graphs \\\n -X PUT \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "graph_ids": [\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"\n ]\n }\'', + }, + }, }, { - "name": "chat", - "endpoint": "/v1/chat", - "httpMethod": "post", - "summary": "Chat completion", - "description": "Generate a chat completion based on the provided messages. The response shown below is for non-streaming. To learn about streaming responses, see the [chat completion guide](https://dev.writer.com/home/chat-completion).", - "stainlessPath": "(resource) chat > (method) chat", - "qualified": "client.chat.chat", - "params": [ + name: 'chat', + endpoint: '/v1/chat', + httpMethod: 'post', + summary: 'Chat completion', + description: + 'Generate a chat completion based on the provided messages. The response shown below is for non-streaming. To learn about streaming responses, see the [chat completion guide](https://dev.writer.com/home/chat-completion).', + stainlessPath: '(resource) chat > (method) chat', + qualified: 'client.chat.chat', + params: [ "messages: { role: 'user' | 'assistant' | 'system' | 'tool'; content?: string | { text: string; type: 'text'; } | { image_url: { url: string; }; type: 'image_url'; }[]; graph_data?: { references?: { files?: object[]; web?: object[]; }; sources?: object[]; status?: 'processing' | 'finished'; subqueries?: { answer: string; query: string; sources: source[]; }[]; }; name?: string; refusal?: string; tool_call_id?: string; tool_calls?: { id: string; function: { arguments: string; name?: string; }; type: 'function'; index?: number; }[]; }[];", - "model: string;", - "logprobs?: boolean;", - "max_tokens?: number;", - "n?: number;", + 'model: string;', + 'logprobs?: boolean;', + 'max_tokens?: number;', + 'n?: number;', "response_format?: { type: 'text' | 'json_schema'; json_schema?: object; };", - "stop?: string[] | string;", - "stream?: boolean;", - "stream_options?: { include_usage: boolean; };", - "temperature?: number;", + 'stop?: string[] | string;', + 'stream?: boolean;', + 'stream_options?: { include_usage: boolean; };', + 'temperature?: number;', "tool_choice?: { value: 'none' | 'auto' | 'required'; } | { value: object; };", "tools?: { function: { name: string; description?: string; parameters?: function_params; }; type: 'function'; } | { function: { graph_ids: string[]; subqueries: boolean; description?: string; query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }; }; type: 'graph'; } | { function: { description: string; model: string; }; type: 'llm'; } | { function: { formality: boolean; length_control: boolean; mask_profanity: boolean; model: 'palmyra-translate'; source_language_code?: string; target_language_code?: string; }; type: 'translation'; } | { function: { model: 'palmyra-vision'; variables: { file_id: string; name: string; }[]; }; type: 'vision'; } | { function: { exclude_domains: string[]; include_domains: string[]; }; type: 'web_search'; }[];", - "top_p?: number;" + 'top_p?: number;', ], - "response": "{ id: string; choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: chat_completion_message; logprobs?: logprobs; }[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: object; prompt_token_details?: object; }; }", - "markdown": "## chat\n\n`client.chat.chat(messages: { role: 'user' | 'assistant' | 'system' | 'tool'; content?: string | { text: string; type: 'text'; } | { image_url: object; type: 'image_url'; }[]; graph_data?: object; name?: string; refusal?: string; tool_call_id?: string; tool_calls?: object[]; }[], model: string, logprobs?: boolean, max_tokens?: number, n?: number, response_format?: { type: 'text' | 'json_schema'; json_schema?: object; }, stop?: string[] | string, stream?: boolean, stream_options?: { include_usage: boolean; }, temperature?: number, tool_choice?: { value: 'none' | 'auto' | 'required'; } | { value: object; }, tools?: { function: function_definition; type: 'function'; } | { function: object; type: 'graph'; } | { function: object; type: 'llm'; } | { function: object; type: 'translation'; } | { function: object; type: 'vision'; } | { function: object; type: 'web_search'; }[], top_p?: number): { id: string; choices: chat_completion_choice[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: chat_completion_usage; }`\n\n**post** `/v1/chat`\n\nGenerate a chat completion based on the provided messages. The response shown below is for non-streaming. To learn about streaming responses, see the [chat completion guide](https://dev.writer.com/home/chat-completion).\n\n### Parameters\n\n- `messages: { role: 'user' | 'assistant' | 'system' | 'tool'; content?: string | { text: string; type: 'text'; } | { image_url: { url: string; }; type: 'image_url'; }[]; graph_data?: { references?: { files?: object[]; web?: object[]; }; sources?: object[]; status?: 'processing' | 'finished'; subqueries?: { answer: string; query: string; sources: source[]; }[]; }; name?: string; refusal?: string; tool_call_id?: string; tool_calls?: { id: string; function: { arguments: string; name?: string; }; type: 'function'; index?: number; }[]; }[]`\n An array of message objects that form the conversation history or context for the model to respond to. The array must contain at least one message.\n\n- `model: string`\n The [ID of the model](https://dev.writer.com/home/models) to use for creating the chat completion. Supports `palmyra-x5`, `palmyra-x4`, `palmyra-fin`, `palmyra-med`, `palmyra-creative`, and `palmyra-x-003-instruct`.\n\n- `logprobs?: boolean`\n Specifies whether to return log probabilities of the output tokens.\n\n- `max_tokens?: number`\n Defines the maximum number of tokens (words and characters) that the model can generate in the response. This can be adjusted to allow for longer or shorter responses as needed. The maximum value varies by model. See the [models overview](/home/models) for more information about the maximum number of tokens for each model.\n\n- `n?: number`\n Specifies the number of completions (responses) to generate from the model in a single request. This parameter allows for generating multiple responses, offering a variety of potential replies from which to choose.\n\n- `response_format?: { type: 'text' | 'json_schema'; json_schema?: object; }`\n The response format to use for the chat completion, available with `palmyra-x4` and `palmyra-x5`.\n\n`text` is the default response format. [JSON Schema](https://json-schema.org/) is supported for structured responses. If you specify `json_schema`, you must also provide a `json_schema` object.\n - `type: 'text' | 'json_schema'`\n The type of response format to use.\n - `json_schema?: object`\n The JSON schema to use for the response format.\n\n- `stop?: string[] | string`\n A token or sequence of tokens that, when generated, will cause the model to stop producing further content. This can be a single token or an array of tokens, acting as a signal to end the output.\n\n- `stream?: boolean`\n Indicates whether the response should be streamed incrementally as it is generated or only returned once fully complete. Streaming can be useful for providing real-time feedback in interactive applications.\n\n- `stream_options?: { include_usage: boolean; }`\n Additional options for streaming.\n - `include_usage: boolean`\n Indicate whether to include usage information.\n\n- `temperature?: number`\n Controls the randomness or creativity of the model's responses. A higher temperature results in more varied and less predictable text, while a lower temperature produces more deterministic and conservative outputs.\n\n- `tool_choice?: { value: 'none' | 'auto' | 'required'; } | { value: object; }`\n Configure how the model will call functions:\n- `auto`: allows the model to automatically choose the tool to use, or not call a tool\n- `none`: disables tool calling; the model will instead generate a message\n- `required`: requires the model to call one or more tools\n\nYou can also use a JSON object to force the model to call a specific tool. For example, `{\"type\": \"function\", \"function\": {\"name\": \"get_current_weather\"}}` requires the model to call the `get_current_weather` function, regardless of the prompt.\n\n- `tools?: { function: { name: string; description?: string; parameters?: function_params; }; type: 'function'; } | { function: { graph_ids: string[]; subqueries: boolean; description?: string; query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }; }; type: 'graph'; } | { function: { description: string; model: string; }; type: 'llm'; } | { function: { formality: boolean; length_control: boolean; mask_profanity: boolean; model: 'palmyra-translate'; source_language_code?: string; target_language_code?: string; }; type: 'translation'; } | { function: { model: 'palmyra-vision'; variables: { file_id: string; name: string; }[]; }; type: 'vision'; } | { function: { exclude_domains: string[]; include_domains: string[]; }; type: 'web_search'; }[]`\n An array containing tool definitions for tools that the model can use to generate responses. The tool definitions use JSON schema. You can define your own functions or use one of the built-in `graph`, `llm`, `translation`, or `vision` tools. Note that you can only use one built-in tool type in the array (only one of `graph`, `llm`, `translation`, or `vision`). You can pass multiple [custom tools](https://dev.writer.com/home/tool-calling) of type `function` in the same request.\n\n- `top_p?: number`\n Sets the threshold for \"nucleus sampling,\" a technique to focus the model's token generation on the most likely subset of tokens. Only tokens with cumulative probability above this threshold are considered, controlling the trade-off between creativity and coherence.\n\n### Returns\n\n- `{ id: string; choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: chat_completion_message; logprobs?: logprobs; }[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: object; prompt_token_details?: object; }; }`\n\n - `id: string`\n - `choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: { content: string; refusal: string; role: 'assistant'; graph_data?: graph_data; llm_data?: object; tool_calls?: tool_call[]; translation_data?: object; web_search_data?: object; }; logprobs?: { content: logprobs_token[]; refusal: logprobs_token[]; }; }[]`\n - `created: number`\n - `model: string`\n - `object: 'chat.completion'`\n - `service_tier?: string`\n - `system_fingerprint?: string`\n - `usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: { reasoning_tokens: number; }; prompt_token_details?: { cached_tokens: number; }; }`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.chat.chat({ messages: [{ role: 'user' }], model: 'model' });\nfor await (const chatCompletionChunk of stream) {\n console.log(chatCompletionChunk);\n}\n```", - "perLanguage": { - "typescript": { - "method": "client.chat.chat", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst chatCompletion = await client.chat.chat({ messages: [{ role: 'user' }], model: 'model' });\n\nconsole.log(chatCompletion.id);" - }, - "python": { - "method": "chat.chat", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfor chat in client.chat.chat(\n messages=[{\n \"role\": \"user\"\n }],\n model=\"model\",\n):\n print(chat)" - }, - "go": { - "method": "client.Chat.Chat", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tchatCompletion, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F(\"model\"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", chatCompletion.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/chat \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"messages\": [\n {\n \"role\": \"user\"\n }\n ],\n \"model\": \"model\"\n }'" - } - } + response: + "{ id: string; choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: chat_completion_message; logprobs?: logprobs; }[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: object; prompt_token_details?: object; }; }", + markdown: + "## chat\n\n`client.chat.chat(messages: { role: 'user' | 'assistant' | 'system' | 'tool'; content?: string | { text: string; type: 'text'; } | { image_url: object; type: 'image_url'; }[]; graph_data?: object; name?: string; refusal?: string; tool_call_id?: string; tool_calls?: object[]; }[], model: string, logprobs?: boolean, max_tokens?: number, n?: number, response_format?: { type: 'text' | 'json_schema'; json_schema?: object; }, stop?: string[] | string, stream?: boolean, stream_options?: { include_usage: boolean; }, temperature?: number, tool_choice?: { value: 'none' | 'auto' | 'required'; } | { value: object; }, tools?: { function: function_definition; type: 'function'; } | { function: object; type: 'graph'; } | { function: object; type: 'llm'; } | { function: object; type: 'translation'; } | { function: object; type: 'vision'; } | { function: object; type: 'web_search'; }[], top_p?: number): { id: string; choices: chat_completion_choice[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: chat_completion_usage; }`\n\n**post** `/v1/chat`\n\nGenerate a chat completion based on the provided messages. The response shown below is for non-streaming. To learn about streaming responses, see the [chat completion guide](https://dev.writer.com/home/chat-completion).\n\n### Parameters\n\n- `messages: { role: 'user' | 'assistant' | 'system' | 'tool'; content?: string | { text: string; type: 'text'; } | { image_url: { url: string; }; type: 'image_url'; }[]; graph_data?: { references?: { files?: object[]; web?: object[]; }; sources?: object[]; status?: 'processing' | 'finished'; subqueries?: { answer: string; query: string; sources: source[]; }[]; }; name?: string; refusal?: string; tool_call_id?: string; tool_calls?: { id: string; function: { arguments: string; name?: string; }; type: 'function'; index?: number; }[]; }[]`\n An array of message objects that form the conversation history or context for the model to respond to. The array must contain at least one message.\n\n- `model: string`\n The [ID of the model](https://dev.writer.com/home/models) to use for creating the chat completion. Supports `palmyra-x5`, `palmyra-x4`, `palmyra-fin`, `palmyra-med`, `palmyra-creative`, and `palmyra-x-003-instruct`.\n\n- `logprobs?: boolean`\n Specifies whether to return log probabilities of the output tokens.\n\n- `max_tokens?: number`\n Defines the maximum number of tokens (words and characters) that the model can generate in the response. This can be adjusted to allow for longer or shorter responses as needed. The maximum value varies by model. See the [models overview](/home/models) for more information about the maximum number of tokens for each model.\n\n- `n?: number`\n Specifies the number of completions (responses) to generate from the model in a single request. This parameter allows for generating multiple responses, offering a variety of potential replies from which to choose.\n\n- `response_format?: { type: 'text' | 'json_schema'; json_schema?: object; }`\n The response format to use for the chat completion, available with `palmyra-x4` and `palmyra-x5`.\n\n`text` is the default response format. [JSON Schema](https://json-schema.org/) is supported for structured responses. If you specify `json_schema`, you must also provide a `json_schema` object.\n - `type: 'text' | 'json_schema'`\n The type of response format to use.\n - `json_schema?: object`\n The JSON schema to use for the response format.\n\n- `stop?: string[] | string`\n A token or sequence of tokens that, when generated, will cause the model to stop producing further content. This can be a single token or an array of tokens, acting as a signal to end the output.\n\n- `stream?: boolean`\n Indicates whether the response should be streamed incrementally as it is generated or only returned once fully complete. Streaming can be useful for providing real-time feedback in interactive applications.\n\n- `stream_options?: { include_usage: boolean; }`\n Additional options for streaming.\n - `include_usage: boolean`\n Indicate whether to include usage information.\n\n- `temperature?: number`\n Controls the randomness or creativity of the model's responses. A higher temperature results in more varied and less predictable text, while a lower temperature produces more deterministic and conservative outputs.\n\n- `tool_choice?: { value: 'none' | 'auto' | 'required'; } | { value: object; }`\n Configure how the model will call functions:\n- `auto`: allows the model to automatically choose the tool to use, or not call a tool\n- `none`: disables tool calling; the model will instead generate a message\n- `required`: requires the model to call one or more tools\n\nYou can also use a JSON object to force the model to call a specific tool. For example, `{\"type\": \"function\", \"function\": {\"name\": \"get_current_weather\"}}` requires the model to call the `get_current_weather` function, regardless of the prompt.\n\n- `tools?: { function: { name: string; description?: string; parameters?: function_params; }; type: 'function'; } | { function: { graph_ids: string[]; subqueries: boolean; description?: string; query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }; }; type: 'graph'; } | { function: { description: string; model: string; }; type: 'llm'; } | { function: { formality: boolean; length_control: boolean; mask_profanity: boolean; model: 'palmyra-translate'; source_language_code?: string; target_language_code?: string; }; type: 'translation'; } | { function: { model: 'palmyra-vision'; variables: { file_id: string; name: string; }[]; }; type: 'vision'; } | { function: { exclude_domains: string[]; include_domains: string[]; }; type: 'web_search'; }[]`\n An array containing tool definitions for tools that the model can use to generate responses. The tool definitions use JSON schema. You can define your own functions or use one of the built-in `graph`, `llm`, `translation`, or `vision` tools. Note that you can only use one built-in tool type in the array (only one of `graph`, `llm`, `translation`, or `vision`). You can pass multiple [custom tools](https://dev.writer.com/home/tool-calling) of type `function` in the same request.\n\n- `top_p?: number`\n Sets the threshold for \"nucleus sampling,\" a technique to focus the model's token generation on the most likely subset of tokens. Only tokens with cumulative probability above this threshold are considered, controlling the trade-off between creativity and coherence.\n\n### Returns\n\n- `{ id: string; choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: chat_completion_message; logprobs?: logprobs; }[]; created: number; model: string; object: 'chat.completion'; service_tier?: string; system_fingerprint?: string; usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: object; prompt_token_details?: object; }; }`\n\n - `id: string`\n - `choices: { finish_reason: 'stop' | 'length' | 'content_filter' | 'tool_calls'; index: number; message: { content: string; refusal: string; role: 'assistant'; graph_data?: graph_data; llm_data?: object; tool_calls?: tool_call[]; translation_data?: object; web_search_data?: object; }; logprobs?: { content: logprobs_token[]; refusal: logprobs_token[]; }; }[]`\n - `created: number`\n - `model: string`\n - `object: 'chat.completion'`\n - `service_tier?: string`\n - `system_fingerprint?: string`\n - `usage?: { completion_tokens: number; prompt_tokens: number; total_tokens: number; completion_tokens_details?: { reasoning_tokens: number; }; prompt_token_details?: { cached_tokens: number; }; }`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.chat.chat({ messages: [{ role: 'user' }], model: 'model' });\nfor await (const chatCompletionChunk of stream) {\n console.log(chatCompletionChunk);\n}\n```", + perLanguage: { + typescript: { + method: 'client.chat.chat', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst chatCompletion = await client.chat.chat({ messages: [{ role: 'user' }], model: 'model' });\n\nconsole.log(chatCompletion.id);", + }, + python: { + method: 'chat.chat', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfor chat in client.chat.chat(\n messages=[{\n "role": "user"\n }],\n model="model",\n):\n print(chat)', + }, + go: { + method: 'client.Chat.Chat', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tchatCompletion, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("model"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chatCompletion.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/chat \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "messages": [\n {\n "role": "user"\n }\n ],\n "model": "model"\n }\'', + }, + }, }, { - "name": "create", - "endpoint": "/v1/completions", - "httpMethod": "post", - "summary": "Text generation", - "description": "Generate text completions using the specified model and prompt. This endpoint is useful for text generation tasks that don't require conversational context.", - "stainlessPath": "(resource) completions > (method) create", - "qualified": "client.completions.create", - "params": [ - "model: string;", - "prompt: string;", - "best_of?: number;", - "max_tokens?: number;", - "random_seed?: number;", - "stop?: string[] | string;", - "stream?: boolean;", - "temperature?: number;", - "top_p?: number;" + name: 'create', + endpoint: '/v1/completions', + httpMethod: 'post', + summary: 'Text generation', + description: + "Generate text completions using the specified model and prompt. This endpoint is useful for text generation tasks that don't require conversational context.", + stainlessPath: '(resource) completions > (method) create', + qualified: 'client.completions.create', + params: [ + 'model: string;', + 'prompt: string;', + 'best_of?: number;', + 'max_tokens?: number;', + 'random_seed?: number;', + 'stop?: string[] | string;', + 'stream?: boolean;', + 'temperature?: number;', + 'top_p?: number;', ], - "response": "{ choices: { text: string; log_probs?: object; }[]; model?: string; }", - "markdown": "## create\n\n`client.completions.create(model: string, prompt: string, best_of?: number, max_tokens?: number, random_seed?: number, stop?: string[] | string, stream?: boolean, temperature?: number, top_p?: number): { choices: object[]; model?: string; }`\n\n**post** `/v1/completions`\n\nGenerate text completions using the specified model and prompt. This endpoint is useful for text generation tasks that don't require conversational context.\n\n### Parameters\n\n- `model: string`\n The [ID of the model](https://dev.writer.com/home/models) to use for generating text. Supports `palmyra-x5`, `palmyra-x4`, `palmyra-fin`, `palmyra-med`, `palmyra-creative`, and `palmyra-x-003-instruct`.\n\n- `prompt: string`\n The input text that the model will process to generate a response.\n\n- `best_of?: number`\n Specifies the number of completions to generate and return the best one. Useful for generating multiple outputs and choosing the best based on some criteria.\n\n- `max_tokens?: number`\n The maximum number of tokens that the model can generate in the response.\n\n- `random_seed?: number`\n A seed used to initialize the random number generator for the model, ensuring reproducibility of the output when the same inputs are provided.\n\n- `stop?: string[] | string`\n Specifies stopping conditions for the model's output generation. This can be an array of strings or a single string that the model will look for as a signal to stop generating further tokens.\n\n- `stream?: boolean`\n Determines whether the model's output should be streamed. If true, the output is generated and sent incrementally, which can be useful for real-time applications.\n\n- `temperature?: number`\n Controls the randomness of the model's outputs. Higher values lead to more random outputs, while lower values make the model more deterministic.\n\n- `top_p?: number`\n Used to control the nucleus sampling, where only the most probable tokens with a cumulative probability of top_p are considered for sampling, providing a way to fine-tune the randomness of predictions.\n\n### Returns\n\n- `{ choices: { text: string; log_probs?: object; }[]; model?: string; }`\n\n - `choices: { text: string; log_probs?: { content: object[]; refusal: object[]; }; }[]`\n - `model?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.completions.create({ model: 'palmyra-x-003-instruct', prompt: 'Write me an SEO article about...' });\nfor await (const completionChunk of stream) {\n console.log(completionChunk);\n}\n```", - "perLanguage": { - "typescript": { - "method": "client.completions.create", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst completion = await client.completions.create({\n model: 'palmyra-x-003-instruct',\n prompt: 'Write me an SEO article about...',\n});\n\nconsole.log(completion.choices);" - }, - "python": { - "method": "completions.create", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfor completion in client.completions.create(\n model=\"palmyra-x-003-instruct\",\n prompt=\"Write me an SEO article about...\",\n):\n print(completion)" - }, - "go": { - "method": "client.Completions.New", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tcompletion, err := client.Completions.New(context.TODO(), writersdk.CompletionNewParams{\n\t\tModel: writersdk.F(\"palmyra-x-003-instruct\"),\n\t\tPrompt: writersdk.F(\"Write me an SEO article about...\"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", completion.Choices)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/completions \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"model\": \"palmyra-x-003-instruct\",\n \"prompt\": \"Write me an SEO article about...\"\n }'" - } - } + response: '{ choices: { text: string; log_probs?: object; }[]; model?: string; }', + markdown: + "## create\n\n`client.completions.create(model: string, prompt: string, best_of?: number, max_tokens?: number, random_seed?: number, stop?: string[] | string, stream?: boolean, temperature?: number, top_p?: number): { choices: object[]; model?: string; }`\n\n**post** `/v1/completions`\n\nGenerate text completions using the specified model and prompt. This endpoint is useful for text generation tasks that don't require conversational context.\n\n### Parameters\n\n- `model: string`\n The [ID of the model](https://dev.writer.com/home/models) to use for generating text. Supports `palmyra-x5`, `palmyra-x4`, `palmyra-fin`, `palmyra-med`, `palmyra-creative`, and `palmyra-x-003-instruct`.\n\n- `prompt: string`\n The input text that the model will process to generate a response.\n\n- `best_of?: number`\n Specifies the number of completions to generate and return the best one. Useful for generating multiple outputs and choosing the best based on some criteria.\n\n- `max_tokens?: number`\n The maximum number of tokens that the model can generate in the response.\n\n- `random_seed?: number`\n A seed used to initialize the random number generator for the model, ensuring reproducibility of the output when the same inputs are provided.\n\n- `stop?: string[] | string`\n Specifies stopping conditions for the model's output generation. This can be an array of strings or a single string that the model will look for as a signal to stop generating further tokens.\n\n- `stream?: boolean`\n Determines whether the model's output should be streamed. If true, the output is generated and sent incrementally, which can be useful for real-time applications.\n\n- `temperature?: number`\n Controls the randomness of the model's outputs. Higher values lead to more random outputs, while lower values make the model more deterministic.\n\n- `top_p?: number`\n Used to control the nucleus sampling, where only the most probable tokens with a cumulative probability of top_p are considered for sampling, providing a way to fine-tune the randomness of predictions.\n\n### Returns\n\n- `{ choices: { text: string; log_probs?: object; }[]; model?: string; }`\n\n - `choices: { text: string; log_probs?: { content: object[]; refusal: object[]; }; }[]`\n - `model?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.completions.create({ model: 'palmyra-x-003-instruct', prompt: 'Write me an SEO article about...' });\nfor await (const completionChunk of stream) {\n console.log(completionChunk);\n}\n```", + perLanguage: { + typescript: { + method: 'client.completions.create', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst completion = await client.completions.create({\n model: 'palmyra-x-003-instruct',\n prompt: 'Write me an SEO article about...',\n});\n\nconsole.log(completion.choices);", + }, + python: { + method: 'completions.create', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfor completion in client.completions.create(\n model="palmyra-x-003-instruct",\n prompt="Write me an SEO article about...",\n):\n print(completion)', + }, + go: { + method: 'client.Completions.New', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tcompletion, err := client.Completions.New(context.TODO(), writersdk.CompletionNewParams{\n\t\tModel: writersdk.F("palmyra-x-003-instruct"),\n\t\tPrompt: writersdk.F("Write me an SEO article about..."),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", completion.Choices)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/completions \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "model": "palmyra-x-003-instruct",\n "prompt": "Write me an SEO article about..."\n }\'', + }, + }, }, { - "name": "list", - "endpoint": "/v1/models", - "httpMethod": "get", - "summary": "List models", - "description": "Retrieve a list of available models that can be used for text generation, chat completions, and other AI tasks.", - "stainlessPath": "(resource) models > (method) list", - "qualified": "client.models.list", - "response": "{ models: { id: string; name: string; }[]; }", - "markdown": "## list\n\n`client.models.list(): { models: object[]; }`\n\n**get** `/v1/models`\n\nRetrieve a list of available models that can be used for text generation, chat completions, and other AI tasks.\n\n### Returns\n\n- `{ models: { id: string; name: string; }[]; }`\n\n - `models: { id: string; name: string; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst models = await client.models.list();\n\nconsole.log(models);\n```", - "perLanguage": { - "typescript": { - "method": "client.models.list", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst models = await client.models.list();\n\nconsole.log(models.models);" - }, - "python": { - "method": "models.list", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nmodels = client.models.list()\nprint(models.models)" - }, - "go": { - "method": "client.Models.List", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tmodels, err := client.Models.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", models.Models)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/models \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + name: 'list', + endpoint: '/v1/models', + httpMethod: 'get', + summary: 'List models', + description: + 'Retrieve a list of available models that can be used for text generation, chat completions, and other AI tasks.', + stainlessPath: '(resource) models > (method) list', + qualified: 'client.models.list', + response: '{ models: { id: string; name: string; }[]; }', + markdown: + "## list\n\n`client.models.list(): { models: object[]; }`\n\n**get** `/v1/models`\n\nRetrieve a list of available models that can be used for text generation, chat completions, and other AI tasks.\n\n### Returns\n\n- `{ models: { id: string; name: string; }[]; }`\n\n - `models: { id: string; name: string; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst models = await client.models.list();\n\nconsole.log(models);\n```", + perLanguage: { + typescript: { + method: 'client.models.list', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst models = await client.models.list();\n\nconsole.log(models.models);", + }, + python: { + method: 'models.list', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nmodels = client.models.list()\nprint(models.models)', + }, + go: { + method: 'client.Models.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tmodels, err := client.Models.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", models.Models)\n}\n', + }, + http: { + example: 'curl https://api.writer.com/v1/models \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "list", - "endpoint": "/v1/graphs", - "httpMethod": "get", - "summary": "List graphs", - "description": "Retrieve a list of Knowledge Graphs.", - "stainlessPath": "(resource) graphs > (method) list", - "qualified": "client.graphs.list", - "params": [ - "after?: string;", - "before?: string;", - "limit?: number;", - "order?: 'asc' | 'desc';" - ], - "response": "{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", - "markdown": "## list\n\n`client.graphs.list(after?: string, before?: string, limit?: number, order?: 'asc' | 'desc'): { id: string; created_at: string; file_status: object; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: object[]; }`\n\n**get** `/v1/graphs`\n\nRetrieve a list of Knowledge Graphs.\n\n### Parameters\n\n- `after?: string`\n The ID of the last object in the previous page. This parameter instructs the API to return the next page of results.\n\n- `before?: string`\n The ID of the first object in the previous page. This parameter instructs the API to return the previous page of results.\n\n- `limit?: number`\n Specifies the maximum number of objects returned in a page. The default value is 50. The minimum value is 1, and the maximum value is 100.\n\n- `order?: 'asc' | 'desc'`\n Specifies the order of the results. Valid values are asc for ascending and desc for descending.\n\n### Returns\n\n- `{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `file_status: { completed: number; failed: number; in_progress: number; total: number; }`\n - `name: string`\n - `type: 'manual' | 'connector' | 'web'`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const graph of client.graphs.list()) {\n console.log(graph);\n}\n```", - "perLanguage": { - "typescript": { - "method": "client.graphs.list", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const graph of client.graphs.list()) {\n console.log(graph.id);\n}" - }, - "python": { - "method": "graphs.list", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\npage = client.graphs.list()\npage = page.data[0]\nprint(page.id)" - }, - "go": { - "method": "client.Graphs.List", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tpage, err := client.Graphs.List(context.TODO(), writersdk.GraphListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", page)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/graphs \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + name: 'list', + endpoint: '/v1/graphs', + httpMethod: 'get', + summary: 'List graphs', + description: 'Retrieve a list of Knowledge Graphs.', + stainlessPath: '(resource) graphs > (method) list', + qualified: 'client.graphs.list', + params: ['after?: string;', 'before?: string;', 'limit?: number;', "order?: 'asc' | 'desc';"], + response: + "{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", + markdown: + "## list\n\n`client.graphs.list(after?: string, before?: string, limit?: number, order?: 'asc' | 'desc'): { id: string; created_at: string; file_status: object; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: object[]; }`\n\n**get** `/v1/graphs`\n\nRetrieve a list of Knowledge Graphs.\n\n### Parameters\n\n- `after?: string`\n The ID of the last object in the previous page. This parameter instructs the API to return the next page of results.\n\n- `before?: string`\n The ID of the first object in the previous page. This parameter instructs the API to return the previous page of results.\n\n- `limit?: number`\n Specifies the maximum number of objects returned in a page. The default value is 50. The minimum value is 1, and the maximum value is 100.\n\n- `order?: 'asc' | 'desc'`\n Specifies the order of the results. Valid values are asc for ascending and desc for descending.\n\n### Returns\n\n- `{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `file_status: { completed: number; failed: number; in_progress: number; total: number; }`\n - `name: string`\n - `type: 'manual' | 'connector' | 'web'`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const graph of client.graphs.list()) {\n console.log(graph);\n}\n```", + perLanguage: { + typescript: { + method: 'client.graphs.list', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const graph of client.graphs.list()) {\n console.log(graph.id);\n}", + }, + python: { + method: 'graphs.list', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\npage = client.graphs.list()\npage = page.data[0]\nprint(page.id)', + }, + go: { + method: 'client.Graphs.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Graphs.List(context.TODO(), writersdk.GraphListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', + }, + http: { + example: 'curl https://api.writer.com/v1/graphs \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "create", - "endpoint": "/v1/graphs", - "httpMethod": "post", - "summary": "Create graph", - "description": "Create a new Knowledge Graph.", - "stainlessPath": "(resource) graphs > (method) create", - "qualified": "client.graphs.create", - "params": [ - "description?: string;", - "name?: string;" - ], - "response": "{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", - "markdown": "## create\n\n`client.graphs.create(description?: string, name?: string): { id: string; created_at: string; name: string; description?: string; urls?: object[]; }`\n\n**post** `/v1/graphs`\n\nCreate a new Knowledge Graph.\n\n### Parameters\n\n- `description?: string`\n A description of the Knowledge Graph (max 255 characters). Omitting this field leaves the description unchanged.\n\n- `name?: string`\n The name of the Knowledge Graph (max 255 characters). Omitting this field leaves the name unchanged.\n\n### Returns\n\n- `{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `name: string`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.create();\n\nconsole.log(graph);\n```", - "perLanguage": { - "typescript": { - "method": "client.graphs.create", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.create();\n\nconsole.log(graph.id);" - }, - "python": { - "method": "graphs.create", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\ngraph = client.graphs.create()\nprint(graph.id)" - }, - "go": { - "method": "client.Graphs.New", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tgraph, err := client.Graphs.New(context.TODO(), writersdk.GraphNewParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", graph.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/graphs \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'" - } - } + name: 'create', + endpoint: '/v1/graphs', + httpMethod: 'post', + summary: 'Create graph', + description: 'Create a new Knowledge Graph.', + stainlessPath: '(resource) graphs > (method) create', + qualified: 'client.graphs.create', + params: ['description?: string;', 'name?: string;'], + response: + "{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", + markdown: + "## create\n\n`client.graphs.create(description?: string, name?: string): { id: string; created_at: string; name: string; description?: string; urls?: object[]; }`\n\n**post** `/v1/graphs`\n\nCreate a new Knowledge Graph.\n\n### Parameters\n\n- `description?: string`\n A description of the Knowledge Graph (max 255 characters). Omitting this field leaves the description unchanged.\n\n- `name?: string`\n The name of the Knowledge Graph (max 255 characters). Omitting this field leaves the name unchanged.\n\n### Returns\n\n- `{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `name: string`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.create();\n\nconsole.log(graph);\n```", + perLanguage: { + typescript: { + method: 'client.graphs.create', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.create();\n\nconsole.log(graph.id);", + }, + python: { + method: 'graphs.create', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ngraph = client.graphs.create()\nprint(graph.id)', + }, + go: { + method: 'client.Graphs.New', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.New(context.TODO(), writersdk.GraphNewParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', + }, + http: { + example: + "curl https://api.writer.com/v1/graphs \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'", + }, + }, }, { - "name": "retrieve", - "endpoint": "/v1/graphs/{graph_id}", - "httpMethod": "get", - "summary": "Retrieve graph", - "description": "Retrieve a Knowledge Graph.", - "stainlessPath": "(resource) graphs > (method) retrieve", - "qualified": "client.graphs.retrieve", - "params": [ - "graph_id: string;" - ], - "response": "{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", - "markdown": "## retrieve\n\n`client.graphs.retrieve(graph_id: string): { id: string; created_at: string; file_status: object; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: object[]; }`\n\n**get** `/v1/graphs/{graph_id}`\n\nRetrieve a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `file_status: { completed: number; failed: number; in_progress: number; total: number; }`\n - `name: string`\n - `type: 'manual' | 'connector' | 'web'`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", - "perLanguage": { - "typescript": { - "method": "client.graphs.retrieve", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);" - }, - "python": { - "method": "graphs.retrieve", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\ngraph = client.graphs.retrieve(\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n)\nprint(graph.id)" - }, - "go": { - "method": "client.Graphs.Get", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tgraph, err := client.Graphs.Get(context.TODO(), \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", graph.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + name: 'retrieve', + endpoint: '/v1/graphs/{graph_id}', + httpMethod: 'get', + summary: 'Retrieve graph', + description: 'Retrieve a Knowledge Graph.', + stainlessPath: '(resource) graphs > (method) retrieve', + qualified: 'client.graphs.retrieve', + params: ['graph_id: string;'], + response: + "{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", + markdown: + "## retrieve\n\n`client.graphs.retrieve(graph_id: string): { id: string; created_at: string; file_status: object; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: object[]; }`\n\n**get** `/v1/graphs/{graph_id}`\n\nRetrieve a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; file_status: { completed: number; failed: number; in_progress: number; total: number; }; name: string; type: 'manual' | 'connector' | 'web'; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `file_status: { completed: number; failed: number; in_progress: number; total: number; }`\n - `name: string`\n - `type: 'manual' | 'connector' | 'web'`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", + perLanguage: { + typescript: { + method: 'client.graphs.retrieve', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.retrieve('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);", + }, + python: { + method: 'graphs.retrieve', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ngraph = client.graphs.retrieve(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(graph.id)', + }, + go: { + method: 'client.Graphs.Get', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.Get(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "update", - "endpoint": "/v1/graphs/{graph_id}", - "httpMethod": "put", - "summary": "Update graph", - "description": "Update the name and description of a Knowledge Graph.", - "stainlessPath": "(resource) graphs > (method) update", - "qualified": "client.graphs.update", - "params": [ - "graph_id: string;", - "description?: string;", - "name?: string;", - "urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[];" + name: 'update', + endpoint: '/v1/graphs/{graph_id}', + httpMethod: 'put', + summary: 'Update graph', + description: 'Update the name and description of a Knowledge Graph.', + stainlessPath: '(resource) graphs > (method) update', + qualified: 'client.graphs.update', + params: [ + 'graph_id: string;', + 'description?: string;', + 'name?: string;', + "urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[];", ], - "response": "{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", - "markdown": "## update\n\n`client.graphs.update(graph_id: string, description?: string, name?: string, urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]): { id: string; created_at: string; name: string; description?: string; urls?: object[]; }`\n\n**put** `/v1/graphs/{graph_id}`\n\nUpdate the name and description of a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `description?: string`\n A description of the Knowledge Graph (max 255 characters). Omitting this field leaves the description unchanged.\n\n- `name?: string`\n The name of the Knowledge Graph (max 255 characters). Omitting this field leaves the name unchanged.\n\n- `urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n An array of web connector URLs to update for this Knowledge Graph. You can only connect URLs to Knowledge Graphs with the type `web`. To clear the list of URLs, set this field to an empty array.\n\n### Returns\n\n- `{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `name: string`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.update('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", - "perLanguage": { - "typescript": { - "method": "client.graphs.update", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.update('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);" - }, - "python": { - "method": "graphs.update", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\ngraph = client.graphs.update(\n graph_id=\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n)\nprint(graph.id)" - }, - "go": { - "method": "client.Graphs.Update", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tgraph, err := client.Graphs.Update(\n\t\tcontext.TODO(),\n\t\t\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n\t\twritersdk.GraphUpdateParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", graph.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -X PUT \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'" - } - } + response: + "{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }", + markdown: + "## update\n\n`client.graphs.update(graph_id: string, description?: string, name?: string, urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]): { id: string; created_at: string; name: string; description?: string; urls?: object[]; }`\n\n**put** `/v1/graphs/{graph_id}`\n\nUpdate the name and description of a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `description?: string`\n A description of the Knowledge Graph (max 255 characters). Omitting this field leaves the description unchanged.\n\n- `name?: string`\n The name of the Knowledge Graph (max 255 characters). Omitting this field leaves the name unchanged.\n\n- `urls?: { type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n An array of web connector URLs to update for this Knowledge Graph. You can only connect URLs to Knowledge Graphs with the type `web`. To clear the list of URLs, set this field to an empty array.\n\n### Returns\n\n- `{ id: string; created_at: string; name: string; description?: string; urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]; }`\n\n - `id: string`\n - `created_at: string`\n - `name: string`\n - `description?: string`\n - `urls?: { status: { status: 'validating' | 'success' | 'error'; error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; }; type: 'single_page' | 'sub_pages'; url: string; exclude_urls?: string[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.update('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", + perLanguage: { + typescript: { + method: 'client.graphs.update', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.update('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);", + }, + python: { + method: 'graphs.update', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ngraph = client.graphs.update(\n graph_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(graph.id)', + }, + go: { + method: 'client.Graphs.Update', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.Update(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\twritersdk.GraphUpdateParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', + }, + http: { + example: + "curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -X PUT \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'", + }, + }, }, { - "name": "delete", - "endpoint": "/v1/graphs/{graph_id}", - "httpMethod": "delete", - "summary": "Delete graph", - "description": "Delete a Knowledge Graph.", - "stainlessPath": "(resource) graphs > (method) delete", - "qualified": "client.graphs.delete", - "params": [ - "graph_id: string;" - ], - "response": "{ id: string; deleted: boolean; }", - "markdown": "## delete\n\n`client.graphs.delete(graph_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/graphs/{graph_id}`\n\nDelete a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.delete('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", - "perLanguage": { - "typescript": { - "method": "client.graphs.delete", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.delete('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);" - }, - "python": { - "method": "graphs.delete", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\ngraph = client.graphs.delete(\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n)\nprint(graph.id)" - }, - "go": { - "method": "client.Graphs.Delete", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tgraph, err := client.Graphs.Delete(context.TODO(), \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", graph.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -X DELETE \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + name: 'delete', + endpoint: '/v1/graphs/{graph_id}', + httpMethod: 'delete', + summary: 'Delete graph', + description: 'Delete a Knowledge Graph.', + stainlessPath: '(resource) graphs > (method) delete', + qualified: 'client.graphs.delete', + params: ['graph_id: string;'], + response: '{ id: string; deleted: boolean; }', + markdown: + "## delete\n\n`client.graphs.delete(graph_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/graphs/{graph_id}`\n\nDelete a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst graph = await client.graphs.delete('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph);\n```", + perLanguage: { + typescript: { + method: 'client.graphs.delete', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst graph = await client.graphs.delete('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e');\n\nconsole.log(graph.id);", + }, + python: { + method: 'graphs.delete', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ngraph = client.graphs.delete(\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(graph.id)', + }, + go: { + method: 'client.Graphs.Delete', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tgraph, err := client.Graphs.Delete(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", graph.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/graphs/$GRAPH_ID \\\n -X DELETE \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "add_file_to_graph", - "endpoint": "/v1/graphs/{graph_id}/file", - "httpMethod": "post", - "summary": "Add file to graph", - "description": "Add a file to a Knowledge Graph.", - "stainlessPath": "(resource) graphs > (method) add_file_to_graph", - "qualified": "client.graphs.addFileToGraph", - "params": [ - "graph_id: string;", - "file_id: string;" - ], - "response": "{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }", - "markdown": "## add_file_to_graph\n\n`client.graphs.addFileToGraph(graph_id: string, file_id: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**post** `/v1/graphs/{graph_id}/file`\n\nAdd a file to a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `file_id: string`\n The unique identifier of the file.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { file_id: 'file_id' });\n\nconsole.log(file);\n```", - "perLanguage": { - "typescript": { - "method": "client.graphs.addFileToGraph", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', {\n file_id: 'file_id',\n});\n\nconsole.log(file.id);" - }, - "python": { - "method": "graphs.add_file_to_graph", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfile = client.graphs.add_file_to_graph(\n graph_id=\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n file_id=\"file_id\",\n)\nprint(file.id)" - }, - "go": { - "method": "client.Graphs.AddFileToGraph", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tfile, err := client.Graphs.AddFileToGraph(\n\t\tcontext.TODO(),\n\t\t\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n\t\twritersdk.GraphAddFileToGraphParams{\n\t\t\tFileID: writersdk.F(\"file_id\"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", file.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/graphs/$GRAPH_ID/file \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"file_id\": \"file_id\"\n }'" - } - } + name: 'add_file_to_graph', + endpoint: '/v1/graphs/{graph_id}/file', + httpMethod: 'post', + summary: 'Add file to graph', + description: 'Add a file to a Knowledge Graph.', + stainlessPath: '(resource) graphs > (method) add_file_to_graph', + qualified: 'client.graphs.addFileToGraph', + params: ['graph_id: string;', 'file_id: string;'], + response: '{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }', + markdown: + "## add_file_to_graph\n\n`client.graphs.addFileToGraph(graph_id: string, file_id: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**post** `/v1/graphs/{graph_id}/file`\n\nAdd a file to a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `file_id: string`\n The unique identifier of the file.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { file_id: 'file_id' });\n\nconsole.log(file);\n```", + perLanguage: { + typescript: { + method: 'client.graphs.addFileToGraph', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', {\n file_id: 'file_id',\n});\n\nconsole.log(file.id);", + }, + python: { + method: 'graphs.add_file_to_graph', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfile = client.graphs.add_file_to_graph(\n graph_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n file_id="file_id",\n)\nprint(file.id)', + }, + go: { + method: 'client.Graphs.AddFileToGraph', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Graphs.AddFileToGraph(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\twritersdk.GraphAddFileToGraphParams{\n\t\t\tFileID: writersdk.F("file_id"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/graphs/$GRAPH_ID/file \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "file_id": "file_id"\n }\'', + }, + }, }, { - "name": "remove_file_from_graph", - "endpoint": "/v1/graphs/{graph_id}/file/{file_id}", - "httpMethod": "delete", - "summary": "Remove file from graph", - "description": "Remove a file from a Knowledge Graph.", - "stainlessPath": "(resource) graphs > (method) remove_file_from_graph", - "qualified": "client.graphs.removeFileFromGraph", - "params": [ - "graph_id: string;", - "file_id: string;" - ], - "response": "{ id: string; deleted: boolean; }", - "markdown": "## remove_file_from_graph\n\n`client.graphs.removeFileFromGraph(graph_id: string, file_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/graphs/{graph_id}/file/{file_id}`\n\nRemove a file from a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.graphs.removeFileFromGraph('file_id', { graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e' });\n\nconsole.log(response);\n```", - "perLanguage": { - "typescript": { - "method": "client.graphs.removeFileFromGraph", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.graphs.removeFileFromGraph('file_id', {\n graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n});\n\nconsole.log(response.id);" - }, - "python": { - "method": "graphs.remove_file_from_graph", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nresponse = client.graphs.remove_file_from_graph(\n file_id=\"file_id\",\n graph_id=\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n)\nprint(response.id)" - }, - "go": { - "method": "client.Graphs.RemoveFileFromGraph", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tresponse, err := client.Graphs.RemoveFileFromGraph(\n\t\tcontext.TODO(),\n\t\t\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\",\n\t\t\"file_id\",\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", response.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/graphs/$GRAPH_ID/file/$FILE_ID \\\n -X DELETE \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + name: 'remove_file_from_graph', + endpoint: '/v1/graphs/{graph_id}/file/{file_id}', + httpMethod: 'delete', + summary: 'Remove file from graph', + description: 'Remove a file from a Knowledge Graph.', + stainlessPath: '(resource) graphs > (method) remove_file_from_graph', + qualified: 'client.graphs.removeFileFromGraph', + params: ['graph_id: string;', 'file_id: string;'], + response: '{ id: string; deleted: boolean; }', + markdown: + "## remove_file_from_graph\n\n`client.graphs.removeFileFromGraph(graph_id: string, file_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/graphs/{graph_id}/file/{file_id}`\n\nRemove a file from a Knowledge Graph.\n\n### Parameters\n\n- `graph_id: string`\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.graphs.removeFileFromGraph('file_id', { graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e' });\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.graphs.removeFileFromGraph', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.graphs.removeFileFromGraph('file_id', {\n graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e',\n});\n\nconsole.log(response.id);", + }, + python: { + method: 'graphs.remove_file_from_graph', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.graphs.remove_file_from_graph(\n file_id="file_id",\n graph_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n)\nprint(response.id)', + }, + go: { + method: 'client.Graphs.RemoveFileFromGraph', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Graphs.RemoveFileFromGraph(\n\t\tcontext.TODO(),\n\t\t"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",\n\t\t"file_id",\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/graphs/$GRAPH_ID/file/$FILE_ID \\\n -X DELETE \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "question", - "endpoint": "/v1/graphs/question", - "httpMethod": "post", - "summary": "Question", - "description": "Ask a question to specified Knowledge Graphs.", - "stainlessPath": "(resource) graphs > (method) question", - "qualified": "client.graphs.question", - "params": [ - "graph_ids: string[];", - "question: string;", - "query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; };", - "stream?: boolean;", - "subqueries?: boolean;" + name: 'question', + endpoint: '/v1/graphs/question', + httpMethod: 'post', + summary: 'Question', + description: 'Ask a question to specified Knowledge Graphs.', + stainlessPath: '(resource) graphs > (method) question', + qualified: 'client.graphs.question', + params: [ + 'graph_ids: string[];', + 'question: string;', + 'query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; };', + 'stream?: boolean;', + 'subqueries?: boolean;', ], - "response": "{ answer: string; question: string; sources: { file_id: string; snippet: string; }[]; references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }; subqueries?: { answer: string; query: string; sources: object[]; }[]; }", - "markdown": "## question\n\n`client.graphs.question(graph_ids: string[], question: string, query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }, stream?: boolean, subqueries?: boolean): { answer: string; question: string; sources: source[]; references?: object; subqueries?: object[]; }`\n\n**post** `/v1/graphs/question`\n\nAsk a question to specified Knowledge Graphs.\n\n### Parameters\n\n- `graph_ids: string[]`\n The unique identifiers of the Knowledge Graphs to query.\n\n- `question: string`\n The question to answer using the Knowledge Graph.\n\n- `query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }`\n Configuration options for Knowledge Graph queries, including search parameters and citation settings.\n - `grounding_level?: number`\n Level of grounding required for responses, controlling how closely answers must be tied to source material. Set lower for grounded outputs, higher for creativity. Higher values (closer to 1.0) allow more creative interpretation, while lower values (closer to 0.0) stick more closely to source material. Range: 0.0-1.0, Default: 0.0.\n - `inline_citations?: boolean`\n Whether to include inline citations in the response, showing which Knowledge Graph sources were used. Default: false.\n - `keyword_threshold?: number`\n Threshold for keyword-based matching when searching Knowledge Graph content. Set higher for stricter relevance, lower for broader range. Higher values (closer to 1.0) require stronger keyword matches, while lower values (closer to 0.0) allow more lenient matching. Range: 0.0-1.0, Default: 0.7.\n - `max_snippets?: number`\n Maximum number of text snippets to retrieve from the Knowledge Graph for context. Works in concert with `search_weight` to control best matches vs broader coverage. While technically supports 1-60, values below 5 may return no results due to RAG implementation. Recommended range: 5-25. Due to RAG system behavior, you may see more snippets than requested. Range: 1-60, Default: 30.\n - `max_subquestions?: number`\n Maximum number of subquestions to generate when processing complex queries. Set higher to improve detail, set lower to reduce response time. Range: 1-10, Default: 6.\n - `max_tokens?: number`\n Maximum number of tokens the model can generate in the response. This controls the length of the AI's answer. Set higher for longer answers, set lower for shorter, faster answers. Range: 100-8000, Default: 4000.\n - `search_weight?: number`\n Weight given to search results when ranking and selecting relevant information. Higher values (closer to 100) prioritize keyword-based matching, while lower values (closer to 0) prioritize semantic similarity matching. Use higher values for exact keyword searches, lower values for conceptual similarity searches. Range: 0-100, Default: 50.\n - `semantic_threshold?: number`\n Threshold for semantic similarity matching when searching Knowledge Graph content. Set higher for stricter relevance, lower for broader range. Higher values (closer to 1.0) require stronger semantic similarity, while lower values (closer to 0.0) allow more lenient semantic matching. Range: 0.0-1.0, Default: 0.7.\n\n- `stream?: boolean`\n Determines whether the model's output should be streamed. If true, the output is generated and sent incrementally, which can be useful for real-time applications.\n\n- `subqueries?: boolean`\n Specify whether to include subqueries.\n\n### Returns\n\n- `{ answer: string; question: string; sources: { file_id: string; snippet: string; }[]; references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }; subqueries?: { answer: string; query: string; sources: object[]; }[]; }`\n\n - `answer: string`\n - `question: string`\n - `sources: { file_id: string; snippet: string; }[]`\n - `references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }`\n - `subqueries?: { answer: string; query: string; sources: { file_id: string; snippet: string; }[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.graphs.question({ graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], question: 'question' });\nfor await (const questionResponseChunk of stream) {\n console.log(questionResponseChunk);\n}\n```", - "perLanguage": { - "typescript": { - "method": "client.graphs.question", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst question = await client.graphs.question({\n graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'],\n question: 'question',\n});\n\nconsole.log(question.answer);" - }, - "python": { - "method": "graphs.question", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfor graph in client.graphs.question(\n graph_ids=[\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"],\n question=\"question\",\n):\n print(graph)" - }, - "go": { - "method": "client.Graphs.Question", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tquestion, err := client.Graphs.Question(context.TODO(), writersdk.GraphQuestionParams{\n\t\tGraphIDs: writersdk.F([]string{\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"}),\n\t\tQuestion: writersdk.F(\"question\"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", question.Answer)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/graphs/question \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"graph_ids\": [\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"\n ],\n \"question\": \"question\"\n }'" - } - } + response: + '{ answer: string; question: string; sources: { file_id: string; snippet: string; }[]; references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }; subqueries?: { answer: string; query: string; sources: object[]; }[]; }', + markdown: + "## question\n\n`client.graphs.question(graph_ids: string[], question: string, query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }, stream?: boolean, subqueries?: boolean): { answer: string; question: string; sources: source[]; references?: object; subqueries?: object[]; }`\n\n**post** `/v1/graphs/question`\n\nAsk a question to specified Knowledge Graphs.\n\n### Parameters\n\n- `graph_ids: string[]`\n The unique identifiers of the Knowledge Graphs to query.\n\n- `question: string`\n The question to answer using the Knowledge Graph.\n\n- `query_config?: { grounding_level?: number; inline_citations?: boolean; keyword_threshold?: number; max_snippets?: number; max_subquestions?: number; max_tokens?: number; search_weight?: number; semantic_threshold?: number; }`\n Configuration options for Knowledge Graph queries, including search parameters and citation settings.\n - `grounding_level?: number`\n Level of grounding required for responses, controlling how closely answers must be tied to source material. Set lower for grounded outputs, higher for creativity. Higher values (closer to 1.0) allow more creative interpretation, while lower values (closer to 0.0) stick more closely to source material. Range: 0.0-1.0, Default: 0.0.\n - `inline_citations?: boolean`\n Whether to include inline citations in the response, showing which Knowledge Graph sources were used. Default: false.\n - `keyword_threshold?: number`\n Threshold for keyword-based matching when searching Knowledge Graph content. Set higher for stricter relevance, lower for broader range. Higher values (closer to 1.0) require stronger keyword matches, while lower values (closer to 0.0) allow more lenient matching. Range: 0.0-1.0, Default: 0.7.\n - `max_snippets?: number`\n Maximum number of text snippets to retrieve from the Knowledge Graph for context. Works in concert with `search_weight` to control best matches vs broader coverage. While technically supports 1-60, values below 5 may return no results due to RAG implementation. Recommended range: 5-25. Due to RAG system behavior, you may see more snippets than requested. Range: 1-60, Default: 30.\n - `max_subquestions?: number`\n Maximum number of subquestions to generate when processing complex queries. Set higher to improve detail, set lower to reduce response time. Range: 1-10, Default: 6.\n - `max_tokens?: number`\n Maximum number of tokens the model can generate in the response. This controls the length of the AI's answer. Set higher for longer answers, set lower for shorter, faster answers. Range: 100-8000, Default: 4000.\n - `search_weight?: number`\n Weight given to search results when ranking and selecting relevant information. Higher values (closer to 100) prioritize keyword-based matching, while lower values (closer to 0) prioritize semantic similarity matching. Use higher values for exact keyword searches, lower values for conceptual similarity searches. Range: 0-100, Default: 50.\n - `semantic_threshold?: number`\n Threshold for semantic similarity matching when searching Knowledge Graph content. Set higher for stricter relevance, lower for broader range. Higher values (closer to 1.0) require stronger semantic similarity, while lower values (closer to 0.0) allow more lenient semantic matching. Range: 0.0-1.0, Default: 0.7.\n\n- `stream?: boolean`\n Determines whether the model's output should be streamed. If true, the output is generated and sent incrementally, which can be useful for real-time applications.\n\n- `subqueries?: boolean`\n Specify whether to include subqueries.\n\n### Returns\n\n- `{ answer: string; question: string; sources: { file_id: string; snippet: string; }[]; references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }; subqueries?: { answer: string; query: string; sources: object[]; }[]; }`\n\n - `answer: string`\n - `question: string`\n - `sources: { file_id: string; snippet: string; }[]`\n - `references?: { files?: { fileId: string; score: number; text: string; cite?: string; page?: number; }[]; web?: { score: number; text: string; title: string; url: string; }[]; }`\n - `subqueries?: { answer: string; query: string; sources: { file_id: string; snippet: string; }[]; }[]`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.graphs.question({ graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], question: 'question' });\nfor await (const questionResponseChunk of stream) {\n console.log(questionResponseChunk);\n}\n```", + perLanguage: { + typescript: { + method: 'client.graphs.question', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst question = await client.graphs.question({\n graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'],\n question: 'question',\n});\n\nconsole.log(question.answer);", + }, + python: { + method: 'graphs.question', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfor graph in client.graphs.question(\n graph_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],\n question="question",\n):\n print(graph)', + }, + go: { + method: 'client.Graphs.Question', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tquestion, err := client.Graphs.Question(context.TODO(), writersdk.GraphQuestionParams{\n\t\tGraphIDs: writersdk.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}),\n\t\tQuestion: writersdk.F("question"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", question.Answer)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/graphs/question \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "graph_ids": [\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"\n ],\n "question": "question"\n }\'', + }, + }, }, { - "name": "retrieve", - "endpoint": "/v1/files/{file_id}", - "httpMethod": "get", - "summary": "Retrieve file", - "description": "Retrieve detailed information about a specific file, including its metadata, status, and associated graphs.", - "stainlessPath": "(resource) files > (method) retrieve", - "qualified": "client.files.retrieve", - "params": [ - "file_id: string;" - ], - "response": "{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }", - "markdown": "## retrieve\n\n`client.files.retrieve(file_id: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**get** `/v1/files/{file_id}`\n\nRetrieve detailed information about a specific file, including its metadata, status, and associated graphs.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.retrieve('file_id');\n\nconsole.log(file);\n```", - "perLanguage": { - "typescript": { - "method": "client.files.retrieve", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.retrieve('file_id');\n\nconsole.log(file.id);" - }, - "python": { - "method": "files.retrieve", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfile = client.files.retrieve(\n \"file_id\",\n)\nprint(file.id)" - }, - "go": { - "method": "client.Files.Get", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tfile, err := client.Files.Get(context.TODO(), \"file_id\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", file.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/files/$FILE_ID \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + name: 'retrieve', + endpoint: '/v1/files/{file_id}', + httpMethod: 'get', + summary: 'Retrieve file', + description: + 'Retrieve detailed information about a specific file, including its metadata, status, and associated graphs.', + stainlessPath: '(resource) files > (method) retrieve', + qualified: 'client.files.retrieve', + params: ['file_id: string;'], + response: '{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }', + markdown: + "## retrieve\n\n`client.files.retrieve(file_id: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**get** `/v1/files/{file_id}`\n\nRetrieve detailed information about a specific file, including its metadata, status, and associated graphs.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.retrieve('file_id');\n\nconsole.log(file);\n```", + perLanguage: { + typescript: { + method: 'client.files.retrieve', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.retrieve('file_id');\n\nconsole.log(file.id);", + }, + python: { + method: 'files.retrieve', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfile = client.files.retrieve(\n "file_id",\n)\nprint(file.id)', + }, + go: { + method: 'client.Files.Get', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Get(context.TODO(), "file_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/files/$FILE_ID \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "delete", - "endpoint": "/v1/files/{file_id}", - "httpMethod": "delete", - "summary": "Delete file", - "description": "Permanently delete a file from the system. This action cannot be undone.", - "stainlessPath": "(resource) files > (method) delete", - "qualified": "client.files.delete", - "params": [ - "file_id: string;" - ], - "response": "{ id: string; deleted: boolean; }", - "markdown": "## delete\n\n`client.files.delete(file_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/files/{file_id}`\n\nPermanently delete a file from the system. This action cannot be undone.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.delete('file_id');\n\nconsole.log(file);\n```", - "perLanguage": { - "typescript": { - "method": "client.files.delete", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.delete('file_id');\n\nconsole.log(file.id);" - }, - "python": { - "method": "files.delete", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfile = client.files.delete(\n \"file_id\",\n)\nprint(file.id)" - }, - "go": { - "method": "client.Files.Delete", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tfile, err := client.Files.Delete(context.TODO(), \"file_id\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", file.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/files/$FILE_ID \\\n -X DELETE \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + name: 'delete', + endpoint: '/v1/files/{file_id}', + httpMethod: 'delete', + summary: 'Delete file', + description: 'Permanently delete a file from the system. This action cannot be undone.', + stainlessPath: '(resource) files > (method) delete', + qualified: 'client.files.delete', + params: ['file_id: string;'], + response: '{ id: string; deleted: boolean; }', + markdown: + "## delete\n\n`client.files.delete(file_id: string): { id: string; deleted: boolean; }`\n\n**delete** `/v1/files/{file_id}`\n\nPermanently delete a file from the system. This action cannot be undone.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `{ id: string; deleted: boolean; }`\n\n - `id: string`\n - `deleted: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.delete('file_id');\n\nconsole.log(file);\n```", + perLanguage: { + typescript: { + method: 'client.files.delete', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.delete('file_id');\n\nconsole.log(file.id);", + }, + python: { + method: 'files.delete', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfile = client.files.delete(\n "file_id",\n)\nprint(file.id)', + }, + go: { + method: 'client.Files.Delete', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Delete(context.TODO(), "file_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/files/$FILE_ID \\\n -X DELETE \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "list", - "endpoint": "/v1/files", - "httpMethod": "get", - "summary": "List files", - "description": "Retrieve a paginated list of files with optional filtering by status, graph association, and file type.", - "stainlessPath": "(resource) files > (method) list", - "qualified": "client.files.list", - "params": [ - "after?: string;", - "before?: string;", - "file_types?: string;", - "graph_id?: string;", - "limit?: number;", + name: 'list', + endpoint: '/v1/files', + httpMethod: 'get', + summary: 'List files', + description: + 'Retrieve a paginated list of files with optional filtering by status, graph association, and file type.', + stainlessPath: '(resource) files > (method) list', + qualified: 'client.files.list', + params: [ + 'after?: string;', + 'before?: string;', + 'file_types?: string;', + 'graph_id?: string;', + 'limit?: number;', "order?: 'asc' | 'desc';", - "status?: 'in_progress' | 'completed' | 'failed';" + "status?: 'in_progress' | 'completed' | 'failed';", ], - "response": "{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }", - "markdown": "## list\n\n`client.files.list(after?: string, before?: string, file_types?: string, graph_id?: string, limit?: number, order?: 'asc' | 'desc', status?: 'in_progress' | 'completed' | 'failed'): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**get** `/v1/files`\n\nRetrieve a paginated list of files with optional filtering by status, graph association, and file type.\n\n### Parameters\n\n- `after?: string`\n The ID of the last object in the previous page. This parameter instructs the API to return the next page of results.\n\n- `before?: string`\n The ID of the first object in the previous page. This parameter instructs the API to return the previous page of results.\n\n- `file_types?: string`\n The extensions of the files to retrieve. Separate multiple extensions with a comma. For example: `pdf,jpg,docx`.\n\n- `graph_id?: string`\n The unique identifier of the graph to which the files belong.\n\n- `limit?: number`\n Specifies the maximum number of objects returned in a page. The default value is 50. The minimum value is 1, and the maximum value is 100.\n\n- `order?: 'asc' | 'desc'`\n Specifies the order of the results. Valid values are asc for ascending and desc for descending.\n\n- `status?: 'in_progress' | 'completed' | 'failed'`\n Specifies the status of the files to retrieve. Valid values are in_progress, completed or failed.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const file of client.files.list()) {\n console.log(file);\n}\n```", - "perLanguage": { - "typescript": { - "method": "client.files.list", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const file of client.files.list()) {\n console.log(file.id);\n}" - }, - "python": { - "method": "files.list", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\npage = client.files.list()\npage = page.data[0]\nprint(page.id)" - }, - "go": { - "method": "client.Files.List", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tpage, err := client.Files.List(context.TODO(), writersdk.FileListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", page)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/files \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + response: '{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }', + markdown: + "## list\n\n`client.files.list(after?: string, before?: string, file_types?: string, graph_id?: string, limit?: number, order?: 'asc' | 'desc', status?: 'in_progress' | 'completed' | 'failed'): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**get** `/v1/files`\n\nRetrieve a paginated list of files with optional filtering by status, graph association, and file type.\n\n### Parameters\n\n- `after?: string`\n The ID of the last object in the previous page. This parameter instructs the API to return the next page of results.\n\n- `before?: string`\n The ID of the first object in the previous page. This parameter instructs the API to return the previous page of results.\n\n- `file_types?: string`\n The extensions of the files to retrieve. Separate multiple extensions with a comma. For example: `pdf,jpg,docx`.\n\n- `graph_id?: string`\n The unique identifier of the graph to which the files belong.\n\n- `limit?: number`\n Specifies the maximum number of objects returned in a page. The default value is 50. The minimum value is 1, and the maximum value is 100.\n\n- `order?: 'asc' | 'desc'`\n Specifies the order of the results. Valid values are asc for ascending and desc for descending.\n\n- `status?: 'in_progress' | 'completed' | 'failed'`\n Specifies the status of the files to retrieve. Valid values are in_progress, completed or failed.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\n// Automatically fetches more pages as needed.\nfor await (const file of client.files.list()) {\n console.log(file);\n}\n```", + perLanguage: { + typescript: { + method: 'client.files.list', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\n// Automatically fetches more pages as needed.\nfor await (const file of client.files.list()) {\n console.log(file.id);\n}", + }, + python: { + method: 'files.list', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\npage = client.files.list()\npage = page.data[0]\nprint(page.id)', + }, + go: { + method: 'client.Files.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpage, err := client.Files.List(context.TODO(), writersdk.FileListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", page)\n}\n', + }, + http: { + example: 'curl https://api.writer.com/v1/files \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "upload", - "endpoint": "/v1/files", - "httpMethod": "post", - "summary": "Upload file", - "description": "Upload a new file to the system. Supports various file formats including PDF, DOC, DOCX, PPT, PPTX, JPG, PNG, EML, HTML, SRT, CSV, XLS, and XLSX.", - "stainlessPath": "(resource) files > (method) upload", - "qualified": "client.files.upload", - "params": [ - "content: string;", - "Content-Disposition: string;", - "graphId?: string;" - ], - "response": "{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }", - "markdown": "## upload\n\n`client.files.upload(content: string, Content-Disposition: string, graphId?: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**post** `/v1/files`\n\nUpload a new file to the system. Supports various file formats including PDF, DOC, DOCX, PPT, PPTX, JPG, PNG, EML, HTML, SRT, CSV, XLS, and XLSX.\n\n### Parameters\n\n- `content: string`\n\n- `Content-Disposition: string`\n\n- `graphId?: string`\n The unique identifier of the Knowledge Graph to associate the uploaded file with.\n\nNote: The response from the upload endpoint does not include the `graphId` field, but the association will be visible when you retrieve the file using the file retrieval endpoint.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.upload({ content: fs.createReadStream('path/to/file'), 'Content-Disposition': 'Content-Disposition' });\n\nconsole.log(file);\n```", - "perLanguage": { - "typescript": { - "method": "client.files.upload", - "example": "import fs from 'fs';\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.upload({\n content: fs.createReadStream('path/to/file'),\n 'Content-Disposition': 'Content-Disposition',\n});\n\nconsole.log(file.id);" - }, - "python": { - "method": "files.upload", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nfile = client.files.upload(\n content=b\"Example data\",\n content_disposition=\"Content-Disposition\",\n)\nprint(file.id)" - }, - "go": { - "method": "client.Files.Upload", - "example": "package main\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tfile, err := client.Files.Upload(context.TODO(), writersdk.FileUploadParams{\n\t\tContent: io.Reader(bytes.NewBuffer([]byte(\"Example data\"))),\n\t\tContentDisposition: writersdk.F(\"Content-Disposition\"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", file.ID)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/files \\\n -H 'Content-Type: text/plain' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -F 'content=@/path/to/content'" - } - } + name: 'upload', + endpoint: '/v1/files', + httpMethod: 'post', + summary: 'Upload file', + description: + 'Upload a new file to the system. Supports various file formats including PDF, DOC, DOCX, PPT, PPTX, JPG, PNG, EML, HTML, SRT, CSV, XLS, and XLSX.', + stainlessPath: '(resource) files > (method) upload', + qualified: 'client.files.upload', + params: ['content: string;', 'Content-Disposition: string;', 'graphId?: string;'], + response: '{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }', + markdown: + "## upload\n\n`client.files.upload(content: string, Content-Disposition: string, graphId?: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**post** `/v1/files`\n\nUpload a new file to the system. Supports various file formats including PDF, DOC, DOCX, PPT, PPTX, JPG, PNG, EML, HTML, SRT, CSV, XLS, and XLSX.\n\n### Parameters\n\n- `content: string`\n\n- `Content-Disposition: string`\n\n- `graphId?: string`\n The unique identifier of the Knowledge Graph to associate the uploaded file with.\n\nNote: The response from the upload endpoint does not include the `graphId` field, but the association will be visible when you retrieve the file using the file retrieval endpoint.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.upload({ content: fs.createReadStream('path/to/file'), 'Content-Disposition': 'Content-Disposition' });\n\nconsole.log(file);\n```", + perLanguage: { + typescript: { + method: 'client.files.upload', + example: + "import fs from 'fs';\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.upload({\n content: fs.createReadStream('path/to/file'),\n 'Content-Disposition': 'Content-Disposition',\n});\n\nconsole.log(file.id);", + }, + python: { + method: 'files.upload', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nfile = client.files.upload(\n content=b"Example data",\n content_disposition="Content-Disposition",\n)\nprint(file.id)', + }, + go: { + method: 'client.Files.Upload', + example: + 'package main\n\nimport (\n\t"bytes"\n\t"context"\n\t"fmt"\n\t"io"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Upload(context.TODO(), writersdk.FileUploadParams{\n\t\tContent: io.Reader(bytes.NewBuffer([]byte("Example data"))),\n\t\tContentDisposition: writersdk.F("Content-Disposition"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', + }, + http: { + example: + "curl https://api.writer.com/v1/files \\\n -H 'Content-Type: text/plain' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -F 'content=@/path/to/content'", + }, + }, }, { - "name": "download", - "endpoint": "/v1/files/{file_id}/download", - "httpMethod": "get", - "summary": "Download file", - "description": "Download the binary content of a file. The response will contain the file data in the appropriate MIME type.", - "stainlessPath": "(resource) files > (method) download", - "qualified": "client.files.download", - "params": [ - "file_id: string;" - ], - "response": "string", - "markdown": "## download\n\n`client.files.download(file_id: string): string`\n\n**get** `/v1/files/{file_id}/download`\n\nDownload the binary content of a file. The response will contain the file data in the appropriate MIME type.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.files.download('file_id');\n\nconsole.log(response);\n\nconst content = await response.blob()\nconsole.log(content)\n```", - "perLanguage": { - "typescript": { - "method": "client.files.download", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.files.download('file_id');\n\nconsole.log(response);\n\nconst content = await response.blob();\nconsole.log(content);" - }, - "python": { - "method": "files.download", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nresponse = client.files.download(\n \"file_id\",\n)\nprint(response)\ncontent = response.read()\nprint(content)" - }, - "go": { - "method": "client.Files.Download", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tresponse, err := client.Files.Download(context.TODO(), \"file_id\")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", response)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/files/$FILE_ID/download \\\n -H \"Authorization: Bearer $WRITER_API_KEY\"" - } - } + name: 'download', + endpoint: '/v1/files/{file_id}/download', + httpMethod: 'get', + summary: 'Download file', + description: + 'Download the binary content of a file. The response will contain the file data in the appropriate MIME type.', + stainlessPath: '(resource) files > (method) download', + qualified: 'client.files.download', + params: ['file_id: string;'], + response: 'string', + markdown: + "## download\n\n`client.files.download(file_id: string): string`\n\n**get** `/v1/files/{file_id}/download`\n\nDownload the binary content of a file. The response will contain the file data in the appropriate MIME type.\n\n### Parameters\n\n- `file_id: string`\n\n### Returns\n\n- `string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.files.download('file_id');\n\nconsole.log(response);\n\nconst content = await response.blob()\nconsole.log(content)\n```", + perLanguage: { + typescript: { + method: 'client.files.download', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.files.download('file_id');\n\nconsole.log(response);\n\nconst content = await response.blob();\nconsole.log(content);", + }, + python: { + method: 'files.download', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.files.download(\n "file_id",\n)\nprint(response)\ncontent = response.read()\nprint(content)', + }, + go: { + method: 'client.Files.Download', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Files.Download(context.TODO(), "file_id")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/files/$FILE_ID/download \\\n -H "Authorization: Bearer $WRITER_API_KEY"', + }, + }, }, { - "name": "retry", - "endpoint": "/v1/files/retry", - "httpMethod": "post", - "summary": "Retry failed files", - "description": "Retry processing of files that previously failed to process. This will re-attempt the processing of the specified files.", - "stainlessPath": "(resource) files > (method) retry", - "qualified": "client.files.retry", - "params": [ - "file_ids: string[];" - ], - "response": "{ success?: boolean; }", - "markdown": "## retry\n\n`client.files.retry(file_ids: string[]): { success?: boolean; }`\n\n**post** `/v1/files/retry`\n\nRetry processing of files that previously failed to process. This will re-attempt the processing of the specified files.\n\n### Parameters\n\n- `file_ids: string[]`\n The unique identifier of the files to retry.\n\n### Returns\n\n- `{ success?: boolean; }`\n\n - `success?: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.files.retry({ file_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(response);\n```", - "perLanguage": { - "typescript": { - "method": "client.files.retry", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.files.retry({ file_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(response.success);" - }, - "python": { - "method": "files.retry", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nresponse = client.files.retry(\n file_ids=[\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"],\n)\nprint(response.success)" - }, - "go": { - "method": "client.Files.Retry", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tresponse, err := client.Files.Retry(context.TODO(), writersdk.FileRetryParams{\n\t\tFileIDs: writersdk.F([]string{\"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"}),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", response.Success)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/files/retry \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"file_ids\": [\n \"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e\"\n ]\n }'" - } - } + name: 'retry', + endpoint: '/v1/files/retry', + httpMethod: 'post', + summary: 'Retry failed files', + description: + 'Retry processing of files that previously failed to process. This will re-attempt the processing of the specified files.', + stainlessPath: '(resource) files > (method) retry', + qualified: 'client.files.retry', + params: ['file_ids: string[];'], + response: '{ success?: boolean; }', + markdown: + "## retry\n\n`client.files.retry(file_ids: string[]): { success?: boolean; }`\n\n**post** `/v1/files/retry`\n\nRetry processing of files that previously failed to process. This will re-attempt the processing of the specified files.\n\n### Parameters\n\n- `file_ids: string[]`\n The unique identifier of the files to retry.\n\n### Returns\n\n- `{ success?: boolean; }`\n\n - `success?: boolean`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.files.retry({ file_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.files.retry', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.files.retry({ file_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] });\n\nconsole.log(response.success);", + }, + python: { + method: 'files.retry', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.files.retry(\n file_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"],\n)\nprint(response.success)', + }, + go: { + method: 'client.Files.Retry', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Files.Retry(context.TODO(), writersdk.FileRetryParams{\n\t\tFileIDs: writersdk.F([]string{"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Success)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/files/retry \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "file_ids": [\n "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"\n ]\n }\'', + }, + }, }, { - "name": "parse_pdf", - "endpoint": "/v1/tools/pdf-parser/{file_id}", - "httpMethod": "post", - "summary": "Parse PDF", - "description": "Parse PDF to other formats.", - "stainlessPath": "(resource) tools > (method) parse_pdf", - "qualified": "client.tools.parsePdf", - "params": [ - "file_id: string;", - "format: 'text' | 'markdown';" - ], - "response": "{ content: string; }", - "markdown": "## parse_pdf\n\n`client.tools.parsePdf(file_id: string, format: 'text' | 'markdown'): { content: string; }`\n\n**post** `/v1/tools/pdf-parser/{file_id}`\n\nParse PDF to other formats.\n\n### Parameters\n\n- `file_id: string`\n\n- `format: 'text' | 'markdown'`\n The format into which the PDF content should be converted.\n\n### Returns\n\n- `{ content: string; }`\n\n - `content: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.tools.parsePdf('file_id', { format: 'text' });\n\nconsole.log(response);\n```", - "perLanguage": { - "typescript": { - "method": "client.tools.parsePdf", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.tools.parsePdf('file_id', { format: 'text' });\n\nconsole.log(response.content);" - }, - "python": { - "method": "tools.parse_pdf", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nresponse = client.tools.parse_pdf(\n file_id=\"file_id\",\n format=\"text\",\n)\nprint(response.content)" - }, - "go": { - "method": "client.Tools.ParsePdf", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tresponse, err := client.Tools.ParsePdf(\n\t\tcontext.TODO(),\n\t\t\"file_id\",\n\t\twritersdk.ToolParsePdfParams{\n\t\t\tFormat: writersdk.F(writersdk.ToolParsePdfParamsFormatText),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", response.Content)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/tools/pdf-parser/$FILE_ID \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"format\": \"text\"\n }'" - } - } + name: 'parse_pdf', + endpoint: '/v1/tools/pdf-parser/{file_id}', + httpMethod: 'post', + summary: 'Parse PDF', + description: 'Parse PDF to other formats.', + stainlessPath: '(resource) tools > (method) parse_pdf', + qualified: 'client.tools.parsePdf', + params: ['file_id: string;', "format: 'text' | 'markdown';"], + response: '{ content: string; }', + markdown: + "## parse_pdf\n\n`client.tools.parsePdf(file_id: string, format: 'text' | 'markdown'): { content: string; }`\n\n**post** `/v1/tools/pdf-parser/{file_id}`\n\nParse PDF to other formats.\n\n### Parameters\n\n- `file_id: string`\n\n- `format: 'text' | 'markdown'`\n The format into which the PDF content should be converted.\n\n### Returns\n\n- `{ content: string; }`\n\n - `content: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.tools.parsePdf('file_id', { format: 'text' });\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.tools.parsePdf', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.tools.parsePdf('file_id', { format: 'text' });\n\nconsole.log(response.content);", + }, + python: { + method: 'tools.parse_pdf', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.tools.parse_pdf(\n file_id="file_id",\n format="text",\n)\nprint(response.content)', + }, + go: { + method: 'client.Tools.ParsePdf', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Tools.ParsePdf(\n\t\tcontext.TODO(),\n\t\t"file_id",\n\t\twritersdk.ToolParsePdfParams{\n\t\t\tFormat: writersdk.F(writersdk.ToolParsePdfParamsFormatText),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Content)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/tools/pdf-parser/$FILE_ID \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "format": "text"\n }\'', + }, + }, }, { - "name": "web_search", - "endpoint": "/v1/tools/web-search", - "httpMethod": "post", - "summary": "Web search", - "description": "Search the web for information about a given query and return relevant results with source URLs.", - "stainlessPath": "(resource) tools > (method) web_search", - "qualified": "client.tools.webSearch", - "params": [ - "chunks_per_source?: number;", - "country?: string;", - "days?: number;", - "exclude_domains?: string[];", - "include_answer?: boolean;", - "include_domains?: string[];", + name: 'web_search', + endpoint: '/v1/tools/web-search', + httpMethod: 'post', + summary: 'Web search', + description: + 'Search the web for information about a given query and return relevant results with source URLs.', + stainlessPath: '(resource) tools > (method) web_search', + qualified: 'client.tools.webSearch', + params: [ + 'chunks_per_source?: number;', + 'country?: string;', + 'days?: number;', + 'exclude_domains?: string[];', + 'include_answer?: boolean;', + 'include_domains?: string[];', "include_raw_content?: 'text' | 'markdown' | boolean;", - "max_results?: number;", - "query?: string;", + 'max_results?: number;', + 'query?: string;', "search_depth?: 'basic' | 'advanced';", - "stream?: boolean;", + 'stream?: boolean;', "time_range?: 'day' | 'week' | 'month' | 'year' | 'd' | 'w' | 'm' | 'y';", - "topic?: 'general' | 'news';" + "topic?: 'general' | 'news';", ], - "response": "{ query: string; sources: { raw_content?: string; url?: string; }[]; answer?: string; }", - "markdown": "## web_search\n\n`client.tools.webSearch(chunks_per_source?: number, country?: string, days?: number, exclude_domains?: string[], include_answer?: boolean, include_domains?: string[], include_raw_content?: 'text' | 'markdown' | boolean, max_results?: number, query?: string, search_depth?: 'basic' | 'advanced', stream?: boolean, time_range?: 'day' | 'week' | 'month' | 'year' | 'd' | 'w' | 'm' | 'y', topic?: 'general' | 'news'): { query: string; sources: object[]; answer?: string; }`\n\n**post** `/v1/tools/web-search`\n\nSearch the web for information about a given query and return relevant results with source URLs.\n\n### Parameters\n\n- `chunks_per_source?: number`\n Only applies when `search_depth` is `advanced`. Specifies how many text segments to extract from each source. Limited to 3 chunks maximum.\n\n- `country?: string`\n Localizes search results to a specific country. Only applies to general topic searches.\n\n- `days?: number`\n For news topic searches, specifies how many days of news coverage to include.\n\n- `exclude_domains?: string[]`\n Domains to exclude from the search. If unset, the search includes all domains.\n\n- `include_answer?: boolean`\n Whether to include a generated answer to the query in the response. If `false`, only search results are returned.\n\n- `include_domains?: string[]`\n Domains to include in the search. If unset, the search includes all domains.\n\n- `include_raw_content?: 'text' | 'markdown' | boolean`\n Controls how raw content is included in search results:\n\n- `text`: Returns plain text without formatting markup\n- `markdown`: Returns structured content with markdown formatting (headers, links, bold text)\n- `true`: Same as `markdown`\n- `false`: Raw content is not included (default if unset)\n\n- `max_results?: number`\n Limits the number of search results returned. Cannot exceed 20 sources.\n\n- `query?: string`\n The search query.\n\n- `search_depth?: 'basic' | 'advanced'`\n Controls search comprehensiveness:\n\n- `basic`: Returns fewer but highly relevant results\n- `advanced`: Performs a deeper search with more results\n\n- `stream?: boolean`\n Enables streaming of search results as they become available.\n\n- `time_range?: 'day' | 'week' | 'month' | 'year' | 'd' | 'w' | 'm' | 'y'`\n Filters results to content published within the specified time range back from the current date. For example, `week` or `w` returns results from the past 7 days.\n\n- `topic?: 'general' | 'news'`\n The search topic category. Use `news` for current events and news articles, or `general` for broader web search.\n\n### Returns\n\n- `{ query: string; sources: { raw_content?: string; url?: string; }[]; answer?: string; }`\n\n - `query: string`\n - `sources: { raw_content?: string; url?: string; }[]`\n - `answer?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.tools.webSearch();\n\nconsole.log(response);\n```", - "perLanguage": { - "typescript": { - "method": "client.tools.webSearch", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.tools.webSearch({\n include_domains: ['dev.writer.com'],\n query: 'How do I get an API key for the Writer API?',\n});\n\nconsole.log(response.query);" - }, - "python": { - "method": "tools.web_search", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nresponse = client.tools.web_search(\n include_domains=[\"dev.writer.com\"],\n query=\"How do I get an API key for the Writer API?\",\n)\nprint(response.query)" - }, - "go": { - "method": "client.Tools.WebSearch", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tresponse, err := client.Tools.WebSearch(context.TODO(), writersdk.ToolWebSearchParams{\n\t\tIncludeDomains: writersdk.F([]string{\"dev.writer.com\"}),\n\t\tQuery: writersdk.F(\"How do I get an API key for the Writer API?\"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", response.Query)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/tools/web-search \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'" - } - } + response: '{ query: string; sources: { raw_content?: string; url?: string; }[]; answer?: string; }', + markdown: + "## web_search\n\n`client.tools.webSearch(chunks_per_source?: number, country?: string, days?: number, exclude_domains?: string[], include_answer?: boolean, include_domains?: string[], include_raw_content?: 'text' | 'markdown' | boolean, max_results?: number, query?: string, search_depth?: 'basic' | 'advanced', stream?: boolean, time_range?: 'day' | 'week' | 'month' | 'year' | 'd' | 'w' | 'm' | 'y', topic?: 'general' | 'news'): { query: string; sources: object[]; answer?: string; }`\n\n**post** `/v1/tools/web-search`\n\nSearch the web for information about a given query and return relevant results with source URLs.\n\n### Parameters\n\n- `chunks_per_source?: number`\n Only applies when `search_depth` is `advanced`. Specifies how many text segments to extract from each source. Limited to 3 chunks maximum.\n\n- `country?: string`\n Localizes search results to a specific country. Only applies to general topic searches.\n\n- `days?: number`\n For news topic searches, specifies how many days of news coverage to include.\n\n- `exclude_domains?: string[]`\n Domains to exclude from the search. If unset, the search includes all domains.\n\n- `include_answer?: boolean`\n Whether to include a generated answer to the query in the response. If `false`, only search results are returned.\n\n- `include_domains?: string[]`\n Domains to include in the search. If unset, the search includes all domains.\n\n- `include_raw_content?: 'text' | 'markdown' | boolean`\n Controls how raw content is included in search results:\n\n- `text`: Returns plain text without formatting markup\n- `markdown`: Returns structured content with markdown formatting (headers, links, bold text)\n- `true`: Same as `markdown`\n- `false`: Raw content is not included (default if unset)\n\n- `max_results?: number`\n Limits the number of search results returned. Cannot exceed 20 sources.\n\n- `query?: string`\n The search query.\n\n- `search_depth?: 'basic' | 'advanced'`\n Controls search comprehensiveness:\n\n- `basic`: Returns fewer but highly relevant results\n- `advanced`: Performs a deeper search with more results\n\n- `stream?: boolean`\n Enables streaming of search results as they become available.\n\n- `time_range?: 'day' | 'week' | 'month' | 'year' | 'd' | 'w' | 'm' | 'y'`\n Filters results to content published within the specified time range back from the current date. For example, `week` or `w` returns results from the past 7 days.\n\n- `topic?: 'general' | 'news'`\n The search topic category. Use `news` for current events and news articles, or `general` for broader web search.\n\n### Returns\n\n- `{ query: string; sources: { raw_content?: string; url?: string; }[]; answer?: string; }`\n\n - `query: string`\n - `sources: { raw_content?: string; url?: string; }[]`\n - `answer?: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst response = await client.tools.webSearch();\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.tools.webSearch', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.tools.webSearch({\n include_domains: ['dev.writer.com'],\n query: 'How do I get an API key for the Writer API?',\n});\n\nconsole.log(response.query);", + }, + python: { + method: 'tools.web_search', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.tools.web_search(\n include_domains=["dev.writer.com"],\n query="How do I get an API key for the Writer API?",\n)\nprint(response.query)', + }, + go: { + method: 'client.Tools.WebSearch', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Tools.WebSearch(context.TODO(), writersdk.ToolWebSearchParams{\n\t\tIncludeDomains: writersdk.F([]string{"dev.writer.com"}),\n\t\tQuery: writersdk.F("How do I get an API key for the Writer API?"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Query)\n}\n', + }, + http: { + example: + "curl https://api.writer.com/v1/tools/web-search \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'", + }, + }, }, { - "name": "translate", - "endpoint": "/v1/translation", - "httpMethod": "post", - "summary": "Translate text", - "description": "Translate text from one language to another.", - "stainlessPath": "(resource) translation > (method) translate", - "qualified": "client.translation.translate", - "params": [ - "formality: boolean;", - "length_control: boolean;", - "mask_profanity: boolean;", + name: 'translate', + endpoint: '/v1/translation', + httpMethod: 'post', + summary: 'Translate text', + description: 'Translate text from one language to another.', + stainlessPath: '(resource) translation > (method) translate', + qualified: 'client.translation.translate', + params: [ + 'formality: boolean;', + 'length_control: boolean;', + 'mask_profanity: boolean;', "model: 'palmyra-translate';", - "source_language_code: string;", - "target_language_code: string;", - "text: string;" + 'source_language_code: string;', + 'target_language_code: string;', + 'text: string;', ], - "response": "{ data: string; }", - "markdown": "## translate\n\n`client.translation.translate(formality: boolean, length_control: boolean, mask_profanity: boolean, model: 'palmyra-translate', source_language_code: string, target_language_code: string, text: string): { data: string; }`\n\n**post** `/v1/translation`\n\nTranslate text from one language to another.\n\n### Parameters\n\n- `formality: boolean`\n Whether to use formal or informal language in the translation. See the [list of languages that support formality](https://dev.writer.com/api-reference/translation-api/language-support#formality). If the language does not support formality, this parameter is ignored.\n\n- `length_control: boolean`\n Whether to control the length of the translated text. See the [list of languages that support length control](https://dev.writer.com/api-reference/translation-api/language-support#length-control). If the language does not support length control, this parameter is ignored.\n\n- `mask_profanity: boolean`\n Whether to mask profane words in the translated text. See the [list of languages that do not support profanity masking](https://dev.writer.com/api-reference/translation-api/language-support#profanity-masking). If the language does not support profanity masking, this parameter is ignored.\n\n- `model: 'palmyra-translate'`\n The model to use for translation.\n\n- `source_language_code: string`\n The [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) language code of the original text to translate. For example, `en` for English, `zh` for Chinese, `fr` for French, `es` for Spanish. If the language has a variant, the code appends the two-digit [ISO-3166 country code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes). For example, Mexican Spanish is `es-MX`. See the [list of supported languages and language codes](https://dev.writer.com/api-reference/translation-api/language-support).\n\n- `target_language_code: string`\n The [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) language code of the target language for the translation. For example, `en` for English, `zh` for Chinese, `fr` for French, `es` for Spanish. If the language has a variant, the code appends the two-digit [ISO-3166 country code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes). For example, Mexican Spanish is `es-MX`. See the [list of supported languages and language codes](https://dev.writer.com/api-reference/translation-api/language-support).\n\n- `text: string`\n The text to translate. Maximum of 100,000 words.\n\n### Returns\n\n- `{ data: string; }`\n\n - `data: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst translationResponse = await client.translation.translate({\n formality: true,\n length_control: true,\n mask_profanity: true,\n model: 'palmyra-translate',\n source_language_code: 'en',\n target_language_code: 'es',\n text: 'Hello, world!',\n});\n\nconsole.log(translationResponse);\n```", - "perLanguage": { - "typescript": { - "method": "client.translation.translate", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst translationResponse = await client.translation.translate({\n formality: true,\n length_control: true,\n mask_profanity: true,\n model: 'palmyra-translate',\n source_language_code: 'en',\n target_language_code: 'es',\n text: 'Hello, world!',\n});\n\nconsole.log(translationResponse.data);" - }, - "python": { - "method": "translation.translate", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\ntranslation_response = client.translation.translate(\n formality=True,\n length_control=True,\n mask_profanity=True,\n model=\"palmyra-translate\",\n source_language_code=\"en\",\n target_language_code=\"es\",\n text=\"Hello, world!\",\n)\nprint(translation_response.data)" - }, - "go": { - "method": "client.Translation.Translate", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\ttranslationResponse, err := client.Translation.Translate(context.TODO(), writersdk.TranslationTranslateParams{\n\t\tTranslationRequest: writersdk.TranslationRequestParam{\n\t\t\tFormality: writersdk.F(true),\n\t\t\tLengthControl: writersdk.F(true),\n\t\t\tMaskProfanity: writersdk.F(true),\n\t\t\tModel: writersdk.F(writersdk.TranslationRequestModelPalmyraTranslate),\n\t\t\tSourceLanguageCode: writersdk.F(\"en\"),\n\t\t\tTargetLanguageCode: writersdk.F(\"es\"),\n\t\t\tText: writersdk.F(\"Hello, world!\"),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", translationResponse.Data)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/translation \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"formality\": true,\n \"length_control\": true,\n \"mask_profanity\": true,\n \"model\": \"palmyra-translate\",\n \"source_language_code\": \"en\",\n \"target_language_code\": \"es\",\n \"text\": \"Hello, world!\"\n }'" - } - } + response: '{ data: string; }', + markdown: + "## translate\n\n`client.translation.translate(formality: boolean, length_control: boolean, mask_profanity: boolean, model: 'palmyra-translate', source_language_code: string, target_language_code: string, text: string): { data: string; }`\n\n**post** `/v1/translation`\n\nTranslate text from one language to another.\n\n### Parameters\n\n- `formality: boolean`\n Whether to use formal or informal language in the translation. See the [list of languages that support formality](https://dev.writer.com/api-reference/translation-api/language-support#formality). If the language does not support formality, this parameter is ignored.\n\n- `length_control: boolean`\n Whether to control the length of the translated text. See the [list of languages that support length control](https://dev.writer.com/api-reference/translation-api/language-support#length-control). If the language does not support length control, this parameter is ignored.\n\n- `mask_profanity: boolean`\n Whether to mask profane words in the translated text. See the [list of languages that do not support profanity masking](https://dev.writer.com/api-reference/translation-api/language-support#profanity-masking). If the language does not support profanity masking, this parameter is ignored.\n\n- `model: 'palmyra-translate'`\n The model to use for translation.\n\n- `source_language_code: string`\n The [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) language code of the original text to translate. For example, `en` for English, `zh` for Chinese, `fr` for French, `es` for Spanish. If the language has a variant, the code appends the two-digit [ISO-3166 country code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes). For example, Mexican Spanish is `es-MX`. See the [list of supported languages and language codes](https://dev.writer.com/api-reference/translation-api/language-support).\n\n- `target_language_code: string`\n The [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) language code of the target language for the translation. For example, `en` for English, `zh` for Chinese, `fr` for French, `es` for Spanish. If the language has a variant, the code appends the two-digit [ISO-3166 country code](https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes). For example, Mexican Spanish is `es-MX`. See the [list of supported languages and language codes](https://dev.writer.com/api-reference/translation-api/language-support).\n\n- `text: string`\n The text to translate. Maximum of 100,000 words.\n\n### Returns\n\n- `{ data: string; }`\n\n - `data: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst translationResponse = await client.translation.translate({\n formality: true,\n length_control: true,\n mask_profanity: true,\n model: 'palmyra-translate',\n source_language_code: 'en',\n target_language_code: 'es',\n text: 'Hello, world!',\n});\n\nconsole.log(translationResponse);\n```", + perLanguage: { + typescript: { + method: 'client.translation.translate', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst translationResponse = await client.translation.translate({\n formality: true,\n length_control: true,\n mask_profanity: true,\n model: 'palmyra-translate',\n source_language_code: 'en',\n target_language_code: 'es',\n text: 'Hello, world!',\n});\n\nconsole.log(translationResponse.data);", + }, + python: { + method: 'translation.translate', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\ntranslation_response = client.translation.translate(\n formality=True,\n length_control=True,\n mask_profanity=True,\n model="palmyra-translate",\n source_language_code="en",\n target_language_code="es",\n text="Hello, world!",\n)\nprint(translation_response.data)', + }, + go: { + method: 'client.Translation.Translate', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\ttranslationResponse, err := client.Translation.Translate(context.TODO(), writersdk.TranslationTranslateParams{\n\t\tTranslationRequest: writersdk.TranslationRequestParam{\n\t\t\tFormality: writersdk.F(true),\n\t\t\tLengthControl: writersdk.F(true),\n\t\t\tMaskProfanity: writersdk.F(true),\n\t\t\tModel: writersdk.F(writersdk.TranslationRequestModelPalmyraTranslate),\n\t\t\tSourceLanguageCode: writersdk.F("en"),\n\t\t\tTargetLanguageCode: writersdk.F("es"),\n\t\t\tText: writersdk.F("Hello, world!"),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", translationResponse.Data)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/translation \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "formality": true,\n "length_control": true,\n "mask_profanity": true,\n "model": "palmyra-translate",\n "source_language_code": "en",\n "target_language_code": "es",\n "text": "Hello, world!"\n }\'', + }, + }, }, { - "name": "analyze", - "endpoint": "/v1/vision", - "httpMethod": "post", - "summary": "Analyze images", - "description": "Submit images and documents with a prompt to generate an analysis. Supports JPG, PNG, PDF, and TXT files up to 7MB each.", - "stainlessPath": "(resource) vision > (method) analyze", - "qualified": "client.vision.analyze", - "params": [ + name: 'analyze', + endpoint: '/v1/vision', + httpMethod: 'post', + summary: 'Analyze images', + description: + 'Submit images and documents with a prompt to generate an analysis. Supports JPG, PNG, PDF, and TXT files up to 7MB each.', + stainlessPath: '(resource) vision > (method) analyze', + qualified: 'client.vision.analyze', + params: [ "model: 'palmyra-vision';", - "prompt: string;", - "variables: { file_id: string; name: string; }[];" + 'prompt: string;', + 'variables: { file_id: string; name: string; }[];', ], - "response": "{ data: string; }", - "markdown": "## analyze\n\n`client.vision.analyze(model: 'palmyra-vision', prompt: string, variables: { file_id: string; name: string; }[]): { data: string; }`\n\n**post** `/v1/vision`\n\nSubmit images and documents with a prompt to generate an analysis. Supports JPG, PNG, PDF, and TXT files up to 7MB each.\n\n### Parameters\n\n- `model: 'palmyra-vision'`\n The model to use for image analysis.\n\n- `prompt: string`\n The prompt to use for the image analysis. The prompt must include the name of each image variable, surrounded by double curly braces (`{{}}`). For example, `Describe the difference between the image {{image_1}} and the image {{image_2}}`.\n\n- `variables: { file_id: string; name: string; }[]`\n\n### Returns\n\n- `{ data: string; }`\n\n - `data: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst visionResponse = await client.vision.analyze({\n model: 'palmyra-vision',\n prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.',\n variables: [{ file_id: 'f1234', name: 'image_1' }, { file_id: 'f9876', name: 'image_2' }],\n});\n\nconsole.log(visionResponse);\n```", - "perLanguage": { - "typescript": { - "method": "client.vision.analyze", - "example": "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst visionResponse = await client.vision.analyze({\n model: 'palmyra-vision',\n prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.',\n variables: [\n { name: 'image_1', file_id: 'f1234' },\n { name: 'image_2', file_id: 'f9876' },\n ],\n});\n\nconsole.log(visionResponse.data);" - }, - "python": { - "method": "vision.analyze", - "example": "import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\nvision_response = client.vision.analyze(\n model=\"palmyra-vision\",\n prompt=\"Describe the difference between the image {{image_1}} and the image {{image_2}}.\",\n variables=[{\n \"name\": \"image_1\",\n \"file_id\": \"f1234\",\n }, {\n \"name\": \"image_2\",\n \"file_id\": \"f9876\",\n }],\n)\nprint(vision_response.data)" - }, - "go": { - "method": "client.Vision.Analyze", - "example": "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tvisionResponse, err := client.Vision.Analyze(context.TODO(), writersdk.VisionAnalyzeParams{\n\t\tVisionRequest: writersdk.VisionRequestParam{\n\t\t\tModel: writersdk.F(writersdk.VisionRequestModelPalmyraVision),\n\t\t\tPrompt: writersdk.F(\"Describe the difference between the image {{image_1}} and the image {{image_2}}.\"),\n\t\t\tVariables: writersdk.F([]writersdk.VisionRequestVariableParam{{\n\t\t\t\tFileID: writersdk.F(\"f1234\"),\n\t\t\t\tName: writersdk.F(\"image_1\"),\n\t\t\t}, {\n\t\t\t\tFileID: writersdk.F(\"f9876\"),\n\t\t\t\tName: writersdk.F(\"image_2\"),\n\t\t\t}}),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", visionResponse.Data)\n}\n" - }, - "http": { - "example": "curl https://api.writer.com/v1/vision \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{\n \"model\": \"palmyra-vision\",\n \"prompt\": \"Describe the difference between the image {{image_1}} and the image {{image_2}}.\",\n \"variables\": [\n {\n \"file_id\": \"f1234\",\n \"name\": \"image_1\"\n },\n {\n \"file_id\": \"f9876\",\n \"name\": \"image_2\"\n }\n ]\n }'" - } - } - } + response: '{ data: string; }', + markdown: + "## analyze\n\n`client.vision.analyze(model: 'palmyra-vision', prompt: string, variables: { file_id: string; name: string; }[]): { data: string; }`\n\n**post** `/v1/vision`\n\nSubmit images and documents with a prompt to generate an analysis. Supports JPG, PNG, PDF, and TXT files up to 7MB each.\n\n### Parameters\n\n- `model: 'palmyra-vision'`\n The model to use for image analysis.\n\n- `prompt: string`\n The prompt to use for the image analysis. The prompt must include the name of each image variable, surrounded by double curly braces (`{{}}`). For example, `Describe the difference between the image {{image_1}} and the image {{image_2}}`.\n\n- `variables: { file_id: string; name: string; }[]`\n\n### Returns\n\n- `{ data: string; }`\n\n - `data: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst visionResponse = await client.vision.analyze({\n model: 'palmyra-vision',\n prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.',\n variables: [{ file_id: 'f1234', name: 'image_1' }, { file_id: 'f9876', name: 'image_2' }],\n});\n\nconsole.log(visionResponse);\n```", + perLanguage: { + typescript: { + method: 'client.vision.analyze', + example: + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst visionResponse = await client.vision.analyze({\n model: 'palmyra-vision',\n prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.',\n variables: [\n { name: 'image_1', file_id: 'f1234' },\n { name: 'image_2', file_id: 'f9876' },\n ],\n});\n\nconsole.log(visionResponse.data);", + }, + python: { + method: 'vision.analyze', + example: + 'import os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\nvision_response = client.vision.analyze(\n model="palmyra-vision",\n prompt="Describe the difference between the image {{image_1}} and the image {{image_2}}.",\n variables=[{\n "name": "image_1",\n "file_id": "f1234",\n }, {\n "name": "image_2",\n "file_id": "f9876",\n }],\n)\nprint(vision_response.data)', + }, + go: { + method: 'client.Vision.Analyze', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tvisionResponse, err := client.Vision.Analyze(context.TODO(), writersdk.VisionAnalyzeParams{\n\t\tVisionRequest: writersdk.VisionRequestParam{\n\t\t\tModel: writersdk.F(writersdk.VisionRequestModelPalmyraVision),\n\t\t\tPrompt: writersdk.F("Describe the difference between the image {{image_1}} and the image {{image_2}}."),\n\t\t\tVariables: writersdk.F([]writersdk.VisionRequestVariableParam{{\n\t\t\t\tFileID: writersdk.F("f1234"),\n\t\t\t\tName: writersdk.F("image_1"),\n\t\t\t}, {\n\t\t\t\tFileID: writersdk.F("f9876"),\n\t\t\t\tName: writersdk.F("image_2"),\n\t\t\t}}),\n\t\t},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", visionResponse.Data)\n}\n', + }, + http: { + example: + 'curl https://api.writer.com/v1/vision \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "model": "palmyra-vision",\n "prompt": "Describe the difference between the image {{image_1}} and the image {{image_2}}.",\n "variables": [\n {\n "file_id": "f1234",\n "name": "image_1"\n },\n {\n "file_id": "f9876",\n "name": "image_2"\n }\n ]\n }\'', + }, + }, + }, ]; const EMBEDDED_READMES: { language: string; content: string }[] = [ { - "language": "go", - "content": "# Writer Go API Library\n\n\"Go\n\nThe Writer Go library provides convenient access to the [Writer REST API](https://dev.writer.com/api-guides/introduction)\nfrom applications written in Go.\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n\n\n```go\nimport (\n\t\"github.com/stainless-sdks/writer-go\" // imported as SDK_PackageName\n)\n```\n\n\n\nOr to pin the version:\n\n\n\n```sh\ngo get -u 'github.com/stainless-sdks/writer-go@v0.0.1'\n```\n\n\n\n## Requirements\n\nThis library requires Go 1.22+.\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\n\t\"github.com/stainless-sdks/writer-go\"\n\t\"github.com/stainless-sdks/writer-go/option\"\n\t\"github.com/stainless-sdks/writer-go/shared\"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"), // defaults to os.LookupEnv(\"WRITER_API_KEY\")\n\t)\n\tchatCompletion, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString(\"Write a haiku about programming\")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F(\"palmyra-x5\"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", chatCompletion.ID)\n}\n\n```\n\n### Request fields\n\nAll request parameters are wrapped in a generic `Field` type,\nwhich we use to distinguish zero values from null or omitted fields.\n\nThis prevents accidentally sending a zero value if you forget a required parameter,\nand enables explicitly sending `null`, `false`, `''`, or `0` on optional parameters.\nAny field not specified is not sent.\n\nTo construct fields with values, use the helpers `String()`, `Int()`, `Float()`, or most commonly, the generic `F[T]()`.\nTo send a null, use `Null[T]()`, and to send a nonconforming value, use `Raw[T](any)`. For example:\n\n```go\nparams := FooParams{\n\tName: SDK_PackageName.F(\"hello\"),\n\n\t// Explicitly send `\"description\": null`\n\tDescription: SDK_PackageName.Null[string](),\n\n\tPoint: SDK_PackageName.F(SDK_PackageName.Point{\n\t\tX: SDK_PackageName.Int(0),\n\t\tY: SDK_PackageName.Int(1),\n\n\t\t// In cases where the API specifies a given type,\n\t\t// but you want to send something else, use `Raw`:\n\t\tZ: SDK_PackageName.Raw[int64](0.01), // sends a float\n\t}),\n}\n```\n\n### Response objects\n\nAll fields in response structs are value types (not pointers or wrappers).\n\nIf a given field is `null`, not present, or invalid, the corresponding field\nwill simply be its zero value.\n\nAll response structs also include a special `JSON` field, containing more detailed\ninformation about each property, which you can use like so:\n\n```go\nif res.Name == \"\" {\n\t// true if `\"name\"` is either not present or explicitly null\n\tres.JSON.Name.IsNull()\n\n\t// true if the `\"name\"` key was not present in the response JSON at all\n\tres.JSON.Name.IsMissing()\n\n\t// When the API returns data that cannot be coerced to the expected type:\n\tif res.JSON.Name.IsInvalid() {\n\t\traw := res.JSON.Name.Raw()\n\n\t\tlegacyName := struct{\n\t\t\tFirst string `json:\"first\"`\n\t\t\tLast string `json:\"last\"`\n\t\t}{}\n\t\tjson.Unmarshal([]byte(raw), &legacyName)\n\t\tname = legacyName.First + \" \" + legacyName.Last\n\t}\n}\n```\n\nThese `.JSON` structs also include an `Extras` map containing\nany properties in the json response that were not specified\nin the struct. This can be useful for API features not yet\npresent in the SDK.\n\n```go\nbody := res.JSON.ExtraFields[\"my_unexpected_field\"].Raw()\n```\n\n### RequestOptions\n\nThis library uses the functional options pattern. Functions defined in the\n`SDK_PackageOptionName` package return a `RequestOption`, which is a closure that mutates a\n`RequestConfig`. These options can be supplied to the client or at individual\nrequests. For example:\n\n```go\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\t// Adds a header to every request made by the client\n\tSDK_PackageOptionName.WithHeader(\"X-Some-Header\", \"custom_header_info\"),\n)\n\nclient.Chat.Chat(context.TODO(), ...,\n\t// Override the header\n\tSDK_PackageOptionName.WithHeader(\"X-Some-Header\", \"some_other_custom_header_info\"),\n\t// Add an undocumented field to the request body, using sjson syntax\n\tSDK_PackageOptionName.WithJSONSet(\"some.json.path\", map[string]string{\"my\": \"object\"}),\n)\n```\n\nSee the [full list of request options](https://pkg.go.dev/github.com/stainless-sdks/writer-go/SDK_PackageOptionName).\n\n### Pagination\n\nThis library provides some conveniences for working with paginated list endpoints.\n\nYou can use `.ListAutoPaging()` methods to iterate through items across all pages:\n\n```go\niter := client.Graphs.ListAutoPaging(context.TODO(), writersdk.GraphListParams{})\n// Automatically fetches more pages as needed.\nfor iter.Next() {\n\tgraph := iter.Current()\n\tfmt.Printf(\"%+v\\n\", graph)\n}\nif err := iter.Err(); err != nil {\n\tpanic(err.Error())\n}\n```\n\nOr you can use simple `.List()` methods to fetch a single page and receive a standard response object\nwith additional helper methods like `.GetNextPage()`, e.g.:\n\n```go\npage, err := client.Graphs.List(context.TODO(), writersdk.GraphListParams{})\nfor page != nil {\n\tfor _, graph := range page.Data {\n\t\tfmt.Printf(\"%+v\\n\", graph)\n\t}\n\tpage, err = page.GetNextPage()\n}\nif err != nil {\n\tpanic(err.Error())\n}\n```\n\n### Errors\n\nWhen the API returns a non-success status code, we return an error with type\n`*SDK_PackageName.Error`. This contains the `StatusCode`, `*http.Request`, and\n`*http.Response` values of the request, as well as the JSON of the error body\n(much like other response objects in the SDK).\n\nTo handle errors, we recommend that you use the `errors.As` pattern:\n\n```go\n_, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString(\"Write a haiku about programming\")),\n\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t}}),\n\tModel: writersdk.F(\"palmyra-x5\"),\n})\nif err != nil {\n\tvar apierr *writersdk.Error\n\tif errors.As(err, &apierr) {\n\t\tprintln(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request\n\t\tprintln(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response\n\t}\n\tpanic(err.Error()) // GET \"/v1/chat\": 400 Bad Request { ... }\n}\n```\n\nWhen other errors occur, they are returned unwrapped; for example,\nif HTTP transport fails, you might receive `*url.Error` wrapping `*net.OpError`.\n\n### Timeouts\n\nRequests do not time out by default; use context to configure a timeout for a request lifecycle.\n\nNote that if a request is [retried](#retries), the context timeout does not start over.\nTo set a per-retry timeout, use `SDK_PackageOptionName.WithRequestTimeout()`.\n\n```go\n// This sets the timeout for the request, including all the retries.\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)\ndefer cancel()\nclient.Chat.Chat(\n\tctx,\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString(\"Write a haiku about programming\")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F(\"palmyra-x5\"),\n\t},\n\t// This sets the per-retry timeout\n\toption.WithRequestTimeout(20*time.Second),\n)\n```\n\n### File uploads\n\nRequest parameters that correspond to file uploads in multipart requests are typed as\n`param.Field[io.Reader]`. The contents of the `io.Reader` will by default be sent as a multipart form\npart with the file name of \"anonymous_file\" and content-type of \"application/octet-stream\".\n\nThe file name and content-type can be customized by implementing `Name() string` or `ContentType()\nstring` on the run-time type of `io.Reader`. Note that `os.File` implements `Name() string`, so a\nfile returned by `os.Open` will be sent with the file name on disk.\n\nWe also provide a helper `SDK_PackageName.FileParam(reader io.Reader, filename string, contentType string)`\nwhich can be used to wrap any `io.Reader` with the appropriate file name and content type.\n\n\n\n### Retries\n\nCertain errors will be automatically retried 7 times by default, with a short exponential backoff.\nWe retry by default all connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit,\nand >=500 Internal errors.\n\nYou can use the `WithMaxRetries` option to configure or disable this:\n\n```go\n// Configure the default for all requests:\nclient := writersdk.NewClient(\n\toption.WithMaxRetries(0), // default is 2\n)\n\n// Override per-request:\nclient.Chat.Chat(\n\tcontext.TODO(),\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString(\"Write a haiku about programming\")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F(\"palmyra-x5\"),\n\t},\n\toption.WithMaxRetries(5),\n)\n```\n\n\n### Accessing raw response data (e.g. response headers)\n\nYou can access the raw HTTP response data by using the `option.WithResponseInto()` request option. This is useful when\nyou need to examine response headers, status codes, or other details.\n\n```go\n// Create a variable to store the HTTP response\nvar response *http.Response\nchatCompletion, err := client.Chat.Chat(\n\tcontext.TODO(),\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString(\"Write a haiku about programming\")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F(\"palmyra-x5\"),\n\t},\n\toption.WithResponseInto(&response),\n)\nif err != nil {\n\t// handle error\n}\nfmt.Printf(\"%+v\\n\", chatCompletion)\n\nfmt.Printf(\"Status Code: %d\\n\", response.StatusCode)\nfmt.Printf(\"Headers: %+#v\\n\", response.Header)\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.Get`, `client.Post`, and other HTTP verbs.\n`RequestOptions` on the client, such as retries, will be respected when making these requests.\n\n```go\nvar (\n // params can be an io.Reader, a []byte, an encoding/json serializable object,\n // or a \"…Params\" struct defined in this library.\n params map[string]interface{}\n\n // result can be an []byte, *http.Response, a encoding/json deserializable object,\n // or a model defined in this library.\n result *http.Response\n)\nerr := client.Post(context.Background(), \"/unspecified\", params, &result)\nif err != nil {\n …\n}\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use either the `SDK_PackageOptionName.WithQuerySet()`\nor the `SDK_PackageOptionName.WithJSONSet()` methods.\n\n```go\nparams := FooNewParams{\n ID: SDK_PackageName.F(\"id_xxxx\"),\n Data: SDK_PackageName.F(FooNewParamsData{\n FirstName: SDK_PackageName.F(\"John\"),\n }),\n}\nclient.Foo.New(context.Background(), params, SDK_PackageOptionName.WithJSONSet(\"data.last_name\", \"Doe\"))\n```\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may either access the raw JSON of the response as a string\nwith `result.JSON.RawJSON()`, or get the raw JSON of a particular field on the result with\n`result.JSON.Foo.Raw()`.\n\nAny fields that are not present on the response struct will be saved and can be accessed by `result.JSON.ExtraFields()` which returns the extra fields as a `map[string]Field`.\n\n### Middleware\n\nWe provide `SDK_PackageOptionName.WithMiddleware` which applies the given\nmiddleware to requests.\n\n```go\nfunc Logger(req *http.Request, next SDK_PackageOptionName.MiddlewareNext) (res *http.Response, err error) {\n\t// Before the request\n\tstart := time.Now()\n\tLogReq(req)\n\n\t// Forward the request to the next handler\n\tres, err = next(req)\n\n\t// Handle stuff after the request\n\tend := time.Now()\n\tLogRes(res, err, start - end)\n\n return res, err\n}\n\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\tSDK_PackageOptionName.WithMiddleware(Logger),\n)\n```\n\nWhen multiple middlewares are provided as variadic arguments, the middlewares\nare applied left to right. If `SDK_PackageOptionName.WithMiddleware` is given\nmultiple times, for example first in the client then the method, the\nmiddleware in the client will run first and the middleware given in the method\nwill run next.\n\nYou may also replace the default `http.Client` with\n`SDK_PackageOptionName.WithHTTPClient(client)`. Only one http client is\naccepted (this overwrites any previous client) and receives requests after any\nmiddleware has been applied.\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/writer-go/issues) with questions, bugs, or suggestions.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n" + language: 'go', + content: + '# Writer Go API Library\n\nGo Reference\n\nThe Writer Go library provides convenient access to the [Writer REST API](https://dev.writer.com/api-guides/introduction)\nfrom applications written in Go.\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n\n\n```go\nimport (\n\t"github.com/stainless-sdks/writer-go" // imported as SDK_PackageName\n)\n```\n\n\n\nOr to pin the version:\n\n\n\n```sh\ngo get -u \'github.com/stainless-sdks/writer-go@v0.0.1\'\n```\n\n\n\n## Requirements\n\nThis library requires Go 1.22+.\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```go\npackage main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n\t"github.com/stainless-sdks/writer-go/shared"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"), // defaults to os.LookupEnv("WRITER_API_KEY")\n\t)\n\tchatCompletion, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", chatCompletion.ID)\n}\n\n```\n\n### Request fields\n\nAll request parameters are wrapped in a generic `Field` type,\nwhich we use to distinguish zero values from null or omitted fields.\n\nThis prevents accidentally sending a zero value if you forget a required parameter,\nand enables explicitly sending `null`, `false`, `\'\'`, or `0` on optional parameters.\nAny field not specified is not sent.\n\nTo construct fields with values, use the helpers `String()`, `Int()`, `Float()`, or most commonly, the generic `F[T]()`.\nTo send a null, use `Null[T]()`, and to send a nonconforming value, use `Raw[T](any)`. For example:\n\n```go\nparams := FooParams{\n\tName: SDK_PackageName.F("hello"),\n\n\t// Explicitly send `"description": null`\n\tDescription: SDK_PackageName.Null[string](),\n\n\tPoint: SDK_PackageName.F(SDK_PackageName.Point{\n\t\tX: SDK_PackageName.Int(0),\n\t\tY: SDK_PackageName.Int(1),\n\n\t\t// In cases where the API specifies a given type,\n\t\t// but you want to send something else, use `Raw`:\n\t\tZ: SDK_PackageName.Raw[int64](0.01), // sends a float\n\t}),\n}\n```\n\n### Response objects\n\nAll fields in response structs are value types (not pointers or wrappers).\n\nIf a given field is `null`, not present, or invalid, the corresponding field\nwill simply be its zero value.\n\nAll response structs also include a special `JSON` field, containing more detailed\ninformation about each property, which you can use like so:\n\n```go\nif res.Name == "" {\n\t// true if `"name"` is either not present or explicitly null\n\tres.JSON.Name.IsNull()\n\n\t// true if the `"name"` key was not present in the response JSON at all\n\tres.JSON.Name.IsMissing()\n\n\t// When the API returns data that cannot be coerced to the expected type:\n\tif res.JSON.Name.IsInvalid() {\n\t\traw := res.JSON.Name.Raw()\n\n\t\tlegacyName := struct{\n\t\t\tFirst string `json:"first"`\n\t\t\tLast string `json:"last"`\n\t\t}{}\n\t\tjson.Unmarshal([]byte(raw), &legacyName)\n\t\tname = legacyName.First + " " + legacyName.Last\n\t}\n}\n```\n\nThese `.JSON` structs also include an `Extras` map containing\nany properties in the json response that were not specified\nin the struct. This can be useful for API features not yet\npresent in the SDK.\n\n```go\nbody := res.JSON.ExtraFields["my_unexpected_field"].Raw()\n```\n\n### RequestOptions\n\nThis library uses the functional options pattern. Functions defined in the\n`SDK_PackageOptionName` package return a `RequestOption`, which is a closure that mutates a\n`RequestConfig`. These options can be supplied to the client or at individual\nrequests. For example:\n\n```go\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\t// Adds a header to every request made by the client\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "custom_header_info"),\n)\n\nclient.Chat.Chat(context.TODO(), ...,\n\t// Override the header\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "some_other_custom_header_info"),\n\t// Add an undocumented field to the request body, using sjson syntax\n\tSDK_PackageOptionName.WithJSONSet("some.json.path", map[string]string{"my": "object"}),\n)\n```\n\nSee the [full list of request options](https://pkg.go.dev/github.com/stainless-sdks/writer-go/SDK_PackageOptionName).\n\n### Pagination\n\nThis library provides some conveniences for working with paginated list endpoints.\n\nYou can use `.ListAutoPaging()` methods to iterate through items across all pages:\n\n```go\niter := client.Graphs.ListAutoPaging(context.TODO(), writersdk.GraphListParams{})\n// Automatically fetches more pages as needed.\nfor iter.Next() {\n\tgraph := iter.Current()\n\tfmt.Printf("%+v\\n", graph)\n}\nif err := iter.Err(); err != nil {\n\tpanic(err.Error())\n}\n```\n\nOr you can use simple `.List()` methods to fetch a single page and receive a standard response object\nwith additional helper methods like `.GetNextPage()`, e.g.:\n\n```go\npage, err := client.Graphs.List(context.TODO(), writersdk.GraphListParams{})\nfor page != nil {\n\tfor _, graph := range page.Data {\n\t\tfmt.Printf("%+v\\n", graph)\n\t}\n\tpage, err = page.GetNextPage()\n}\nif err != nil {\n\tpanic(err.Error())\n}\n```\n\n### Errors\n\nWhen the API returns a non-success status code, we return an error with type\n`*SDK_PackageName.Error`. This contains the `StatusCode`, `*http.Request`, and\n`*http.Response` values of the request, as well as the JSON of the error body\n(much like other response objects in the SDK).\n\nTo handle errors, we recommend that you use the `errors.As` pattern:\n\n```go\n_, err := client.Chat.Chat(context.TODO(), writersdk.ChatChatParams{\n\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t}}),\n\tModel: writersdk.F("palmyra-x5"),\n})\nif err != nil {\n\tvar apierr *writersdk.Error\n\tif errors.As(err, &apierr) {\n\t\tprintln(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request\n\t\tprintln(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response\n\t}\n\tpanic(err.Error()) // GET "/v1/chat": 400 Bad Request { ... }\n}\n```\n\nWhen other errors occur, they are returned unwrapped; for example,\nif HTTP transport fails, you might receive `*url.Error` wrapping `*net.OpError`.\n\n### Timeouts\n\nRequests do not time out by default; use context to configure a timeout for a request lifecycle.\n\nNote that if a request is [retried](#retries), the context timeout does not start over.\nTo set a per-retry timeout, use `SDK_PackageOptionName.WithRequestTimeout()`.\n\n```go\n// This sets the timeout for the request, including all the retries.\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)\ndefer cancel()\nclient.Chat.Chat(\n\tctx,\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t},\n\t// This sets the per-retry timeout\n\toption.WithRequestTimeout(20*time.Second),\n)\n```\n\n### File uploads\n\nRequest parameters that correspond to file uploads in multipart requests are typed as\n`param.Field[io.Reader]`. The contents of the `io.Reader` will by default be sent as a multipart form\npart with the file name of "anonymous_file" and content-type of "application/octet-stream".\n\nThe file name and content-type can be customized by implementing `Name() string` or `ContentType()\nstring` on the run-time type of `io.Reader`. Note that `os.File` implements `Name() string`, so a\nfile returned by `os.Open` will be sent with the file name on disk.\n\nWe also provide a helper `SDK_PackageName.FileParam(reader io.Reader, filename string, contentType string)`\nwhich can be used to wrap any `io.Reader` with the appropriate file name and content type.\n\n\n\n### Retries\n\nCertain errors will be automatically retried 7 times by default, with a short exponential backoff.\nWe retry by default all connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit,\nand >=500 Internal errors.\n\nYou can use the `WithMaxRetries` option to configure or disable this:\n\n```go\n// Configure the default for all requests:\nclient := writersdk.NewClient(\n\toption.WithMaxRetries(0), // default is 2\n)\n\n// Override per-request:\nclient.Chat.Chat(\n\tcontext.TODO(),\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t},\n\toption.WithMaxRetries(5),\n)\n```\n\n\n### Accessing raw response data (e.g. response headers)\n\nYou can access the raw HTTP response data by using the `option.WithResponseInto()` request option. This is useful when\nyou need to examine response headers, status codes, or other details.\n\n```go\n// Create a variable to store the HTTP response\nvar response *http.Response\nchatCompletion, err := client.Chat.Chat(\n\tcontext.TODO(),\n\twritersdk.ChatChatParams{\n\t\tMessages: writersdk.F([]writersdk.ChatChatParamsMessage{{\n\t\t\tContent: writersdk.F[writersdk.ChatChatParamsMessagesContentUnion](shared.UnionString("Write a haiku about programming")),\n\t\t\tRole: writersdk.F(writersdk.ChatChatParamsMessagesRoleUser),\n\t\t}}),\n\t\tModel: writersdk.F("palmyra-x5"),\n\t},\n\toption.WithResponseInto(&response),\n)\nif err != nil {\n\t// handle error\n}\nfmt.Printf("%+v\\n", chatCompletion)\n\nfmt.Printf("Status Code: %d\\n", response.StatusCode)\nfmt.Printf("Headers: %+#v\\n", response.Header)\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.Get`, `client.Post`, and other HTTP verbs.\n`RequestOptions` on the client, such as retries, will be respected when making these requests.\n\n```go\nvar (\n // params can be an io.Reader, a []byte, an encoding/json serializable object,\n // or a "…Params" struct defined in this library.\n params map[string]interface{}\n\n // result can be an []byte, *http.Response, a encoding/json deserializable object,\n // or a model defined in this library.\n result *http.Response\n)\nerr := client.Post(context.Background(), "/unspecified", params, &result)\nif err != nil {\n …\n}\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use either the `SDK_PackageOptionName.WithQuerySet()`\nor the `SDK_PackageOptionName.WithJSONSet()` methods.\n\n```go\nparams := FooNewParams{\n ID: SDK_PackageName.F("id_xxxx"),\n Data: SDK_PackageName.F(FooNewParamsData{\n FirstName: SDK_PackageName.F("John"),\n }),\n}\nclient.Foo.New(context.Background(), params, SDK_PackageOptionName.WithJSONSet("data.last_name", "Doe"))\n```\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may either access the raw JSON of the response as a string\nwith `result.JSON.RawJSON()`, or get the raw JSON of a particular field on the result with\n`result.JSON.Foo.Raw()`.\n\nAny fields that are not present on the response struct will be saved and can be accessed by `result.JSON.ExtraFields()` which returns the extra fields as a `map[string]Field`.\n\n### Middleware\n\nWe provide `SDK_PackageOptionName.WithMiddleware` which applies the given\nmiddleware to requests.\n\n```go\nfunc Logger(req *http.Request, next SDK_PackageOptionName.MiddlewareNext) (res *http.Response, err error) {\n\t// Before the request\n\tstart := time.Now()\n\tLogReq(req)\n\n\t// Forward the request to the next handler\n\tres, err = next(req)\n\n\t// Handle stuff after the request\n\tend := time.Now()\n\tLogRes(res, err, start - end)\n\n return res, err\n}\n\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\tSDK_PackageOptionName.WithMiddleware(Logger),\n)\n```\n\nWhen multiple middlewares are provided as variadic arguments, the middlewares\nare applied left to right. If `SDK_PackageOptionName.WithMiddleware` is given\nmultiple times, for example first in the client then the method, the\nmiddleware in the client will run first and the middleware given in the method\nwill run next.\n\nYou may also replace the default `http.Client` with\n`SDK_PackageOptionName.WithHTTPClient(client)`. Only one http client is\naccepted (this overwrites any previous client) and receives requests after any\nmiddleware has been applied.\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/writer-go/issues) with questions, bugs, or suggestions.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n', }, { - "language": "python", - "content": "# Writer Python API library\n\n\n[![PyPI version](https://img.shields.io/pypi/v/writer-sdk.svg?label=pypi%20(stable))](https://pypi.org/project/writer-sdk/)\n\nThe Writer Python library provides convenient access to the Writer REST API from any Python 3.9+\napplication. The library includes type definitions for all request params and response fields,\nand offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nThe REST API documentation can be found on [dev.writer.com](https://dev.writer.com/api-guides/introduction). The full API of this library can be found in [api.md](api.md).\n\n## Installation\n\n```sh\n# install from PyPI\npip install writer-sdk\n```\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```python\nimport os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\n\nchat_completion = client.chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n)\nprint(chat_completion.id)\n```\n\nWhile you can provide an `api_key` keyword argument,\nwe recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)\nto add `WRITER_API_KEY=\"My API Key\"` to your `.env` file\nso that your API Key is not stored in source control.\n\n## Async usage\n\nSimply import `AsyncWriter` instead of `Writer` and use `await` with each API call:\n\n```python\nimport os\nimport asyncio\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n)\n\nasync def main() -> None:\n chat_completion = await client.chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n )\n print(chat_completion.id)\n\nasyncio.run(main())\n```\n\nFunctionality between the synchronous and asynchronous clients is otherwise identical.\n\n### With aiohttp\n\nBy default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.\n\nYou can enable this by installing `aiohttp`:\n\n```sh\n# install from PyPI\npip install writer-sdk[aiohttp]\n```\n\nThen you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:\n\n```python\nimport os\nimport asyncio\nfrom writerai import DefaultAioHttpClient\nfrom writerai import AsyncWriter\n\nasync def main() -> None:\n async with AsyncWriter(\n api_key=os.environ.get(\"WRITER_API_KEY\"), # This is the default and can be omitted\n http_client=DefaultAioHttpClient(),\n) as client:\n chat_completion = await client.chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n )\n print(chat_completion.id)\n\nasyncio.run(main())\n```\n\n## Streaming responses\n\nWe provide support for streaming responses using Server Side Events (SSE).\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nstream = client.chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n stream=True,\n)\nfor chat_completion in stream:\n print(chat_completion.id)\n```\n\nThe async client uses the exact same interface.\n\n```python\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter()\n\nstream = await client.chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n stream=True,\n)\nasync for chat_completion in stream:\n print(chat_completion.id)\n```\n\n## Using types\n\nNested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:\n\n- Serializing back into JSON, `model.to_json()`\n- Converting to a dictionary, `model.to_dict()`\n\nTyped requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.\n\n## Pagination\n\nList methods in the Writer API are paginated.\n\nThis library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nall_graphs = []\n# Automatically fetches more pages as needed.\nfor graph in client.graphs.list():\n # Do something with graph here\n all_graphs.append(graph)\nprint(all_graphs)\n```\n\nOr, asynchronously:\n\n```python\nimport asyncio\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter()\n\nasync def main() -> None:\n all_graphs = []\n # Iterate through items across all pages, issuing requests as needed.\n async for graph in client.graphs.list():\n all_graphs.append(graph)\n print(all_graphs)\n\nasyncio.run(main())\n```\n\nAlternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:\n\n```python\nfirst_page = await client.graphs.list()\nif first_page.has_next_page():\n print(f\"will fetch next page using these details: {first_page.next_page_info()}\")\n next_page = await first_page.get_next_page()\n print(f\"number of items we just fetched: {len(next_page.data)}\")\n\n# Remove `await` for non-async usage.\n```\n\nOr just work directly with the returned data:\n\n```python\nfirst_page = await client.graphs.list()\n\nprint(f\"next page cursor: {first_page.after}\") # => \"next page cursor: ...\"\nfor graph in first_page.data:\n print(graph.id)\n\n# Remove `await` for non-async usage.\n```\n\n## Nested params\n\nNested parameters are dictionaries, typed using `TypedDict`, for example:\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nchat_completion = client.chat.chat(\n messages=[{\n \"role\": \"user\"\n }],\n model=\"model\",\n response_format={\n \"type\": \"text\"\n },\n)\nprint(chat_completion.response_format)\n```\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `writerai.APIConnectionError` is raised.\n\nWhen the API returns a non-success status code (that is, 4xx or 5xx\nresponse), a subclass of `writerai.APIStatusError` is raised, containing `status_code` and `response` properties.\n\nAll errors inherit from `writerai.APIError`.\n\n```python\nimport writerai\nfrom writerai import Writer\n\nclient = Writer()\n\ntry:\n client.chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n )\nexcept writerai.APIConnectionError as e:\n print(\"The server could not be reached\")\n print(e.__cause__) # an underlying Exception, likely raised within httpx.\nexcept writerai.RateLimitError as e:\n print(\"A 429 status code was received; we should back off a bit.\")\nexcept writerai.APIStatusError as e:\n print(\"Another non-200-range status code was received\")\n print(e.status_code)\n print(e.response)\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors are automatically retried 7 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors are all retried by default.\n\nYou can use the `max_retries` option to configure or disable retry settings:\n\n```python\nfrom writerai import Writer\n\n# Configure the default for all requests:\nclient = Writer(\n # default is 2\n max_retries=0,\n)\n\n# Or, configure per-request:\nclient.with_options(max_retries = 5).chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n)\n```\n\n### Timeouts\n\nBy default requests time out after 3 minutes. You can configure this with a `timeout` option,\nwhich accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:\n\n```python\nfrom writerai import Writer\n\n# Configure the default for all requests:\nclient = Writer(\n # 20 seconds (default is 3 minutes)\n timeout=20.0,\n)\n\n# More granular control:\nclient = Writer(\n timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),\n)\n\n# Override per-request:\nclient.with_options(timeout = 5.0).chat.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n)\n```\n\nOn timeout, an `APITimeoutError` is thrown.\n\nNote that requests that time out are [retried twice by default](#retries).\n\n\n\n## Advanced\n\n### Logging\n\nWe use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.\n\nYou can enable logging by setting the environment variable `WRITER_LOG` to `info`.\n\n```shell\n$ export WRITER_LOG=info\n```\n\nOr to `debug` for more verbose logging.\n\n### How to tell whether `None` means `null` or missing\n\nIn an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:\n\n```py\nif response.my_field is None:\n if 'my_field' not in response.model_fields_set:\n print('Got json like {}, without a \"my_field\" key present at all.')\n else:\n print('Got json like {\"my_field\": null}.')\n```\n\n### Accessing raw response data (e.g. headers)\n\nThe \"raw\" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,\n\n```py\nfrom writerai import Writer\n\nclient = Writer()\nresponse = client.chat.with_raw_response.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n)\nprint(response.headers.get('X-My-Header'))\n\nchat = response.parse() # get the object that `chat.chat()` would have returned\nprint(chat.id)\n```\n\nThese methods return an [`APIResponse`](https://github.com/writer/writer-python/tree/main/src/writerai/_response.py) object.\n\nThe async client returns an [`AsyncAPIResponse`](https://github.com/writer/writer-python/tree/main/src/writerai/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.\n\n#### `.with_streaming_response`\n\nThe above interface eagerly reads the full response body when you make the request, which may not always be what you want.\n\nTo stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.\n\n```python\nwith client.chat.with_streaming_response.chat(\n messages=[{\n \"content\": \"Write a haiku about programming\",\n \"role\": \"user\",\n }],\n model=\"palmyra-x5\",\n) as response :\n print(response.headers.get('X-My-Header'))\n\n for line in response.iter_lines():\n print(line)\n```\n\nThe context manager is required so that the response will reliably be closed.\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API.\n\nIf you need to access undocumented endpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other\nhttp verbs. Options on the client will be respected (such as retries) when making this request.\n\n```py\nimport httpx\n\nresponse = client.post(\n \"/foo\",\n cast_to=httpx.Response,\n body={\"my_param\": True},\n)\n\nprint(response.headers.get(\"x-foo\"))\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You\ncan also get all the extra fields on the Pydantic model as a dict with\n[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).\n\n### Configuring the HTTP client\n\nYou can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:\n\n- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)\n- Custom [transports](https://www.python-httpx.org/advanced/transports/)\n- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality\n\n```python\nimport httpx\nfrom writerai import Writer, DefaultHttpxClient\n\nclient = Writer(\n # Or use the `WRITER_BASE_URL` env var\n base_url=\"http://my.test.server.example.com:8083\",\n http_client=DefaultHttpxClient(proxy=\"http://my.test.proxy.example.com\", transport=httpx.HTTPTransport(local_address=\"0.0.0.0\")),\n)\n```\n\nYou can also customize the client on a per-request basis by using `with_options()`:\n\n```python\nclient.with_options(http_client=DefaultHttpxClient(...))\n```\n\n### Managing HTTP resources\n\nBy default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.\n\n```py\nfrom writerai import Writer\n\nwith Writer() as client:\n # make requests here\n ...\n\n# HTTP client is now closed\n```\n\n## Versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/writer/writer-python/issues) with questions, bugs, or suggestions.\n\n### Determining the installed version\n\nIf you've upgraded to the latest version but aren't seeing any new features you were expecting then your python environment is likely still using an older version.\n\nYou can determine the version that is being used at runtime with:\n\n```py\nimport writerai\nprint(writerai.__version__)\n```\n\n## Requirements\n\nPython 3.9 or higher.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n" + language: 'python', + content: + '# Writer Python API library\n\n\n[![PyPI version](https://img.shields.io/pypi/v/writer-sdk.svg?label=pypi%20(stable))](https://pypi.org/project/writer-sdk/)\n\nThe Writer Python library provides convenient access to the Writer REST API from any Python 3.9+\napplication. The library includes type definitions for all request params and response fields,\nand offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nThe REST API documentation can be found on [dev.writer.com](https://dev.writer.com/api-guides/introduction). The full API of this library can be found in [api.md](api.md).\n\n## Installation\n\n```sh\n# install from PyPI\npip install writer-sdk\n```\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```python\nimport os\nfrom writerai import Writer\n\nclient = Writer(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\n\nchat_completion = client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\nprint(chat_completion.id)\n```\n\nWhile you can provide an `api_key` keyword argument,\nwe recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)\nto add `WRITER_API_KEY="My API Key"` to your `.env` file\nso that your API Key is not stored in source control.\n\n## Async usage\n\nSimply import `AsyncWriter` instead of `Writer` and use `await` with each API call:\n\n```python\nimport os\nimport asyncio\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n)\n\nasync def main() -> None:\n chat_completion = await client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n )\n print(chat_completion.id)\n\nasyncio.run(main())\n```\n\nFunctionality between the synchronous and asynchronous clients is otherwise identical.\n\n### With aiohttp\n\nBy default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.\n\nYou can enable this by installing `aiohttp`:\n\n```sh\n# install from PyPI\npip install writer-sdk[aiohttp]\n```\n\nThen you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:\n\n```python\nimport os\nimport asyncio\nfrom writerai import DefaultAioHttpClient\nfrom writerai import AsyncWriter\n\nasync def main() -> None:\n async with AsyncWriter(\n api_key=os.environ.get("WRITER_API_KEY"), # This is the default and can be omitted\n http_client=DefaultAioHttpClient(),\n) as client:\n chat_completion = await client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n )\n print(chat_completion.id)\n\nasyncio.run(main())\n```\n\n## Streaming responses\n\nWe provide support for streaming responses using Server Side Events (SSE).\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nstream = client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n stream=True,\n)\nfor chat_completion in stream:\n print(chat_completion.id)\n```\n\nThe async client uses the exact same interface.\n\n```python\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter()\n\nstream = await client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n stream=True,\n)\nasync for chat_completion in stream:\n print(chat_completion.id)\n```\n\n## Using types\n\nNested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:\n\n- Serializing back into JSON, `model.to_json()`\n- Converting to a dictionary, `model.to_dict()`\n\nTyped requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.\n\n## Pagination\n\nList methods in the Writer API are paginated.\n\nThis library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually:\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nall_graphs = []\n# Automatically fetches more pages as needed.\nfor graph in client.graphs.list():\n # Do something with graph here\n all_graphs.append(graph)\nprint(all_graphs)\n```\n\nOr, asynchronously:\n\n```python\nimport asyncio\nfrom writerai import AsyncWriter\n\nclient = AsyncWriter()\n\nasync def main() -> None:\n all_graphs = []\n # Iterate through items across all pages, issuing requests as needed.\n async for graph in client.graphs.list():\n all_graphs.append(graph)\n print(all_graphs)\n\nasyncio.run(main())\n```\n\nAlternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages:\n\n```python\nfirst_page = await client.graphs.list()\nif first_page.has_next_page():\n print(f"will fetch next page using these details: {first_page.next_page_info()}")\n next_page = await first_page.get_next_page()\n print(f"number of items we just fetched: {len(next_page.data)}")\n\n# Remove `await` for non-async usage.\n```\n\nOr just work directly with the returned data:\n\n```python\nfirst_page = await client.graphs.list()\n\nprint(f"next page cursor: {first_page.after}") # => "next page cursor: ..."\nfor graph in first_page.data:\n print(graph.id)\n\n# Remove `await` for non-async usage.\n```\n\n## Nested params\n\nNested parameters are dictionaries, typed using `TypedDict`, for example:\n\n```python\nfrom writerai import Writer\n\nclient = Writer()\n\nchat_completion = client.chat.chat(\n messages=[{\n "role": "user"\n }],\n model="model",\n response_format={\n "type": "text"\n },\n)\nprint(chat_completion.response_format)\n```\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `writerai.APIConnectionError` is raised.\n\nWhen the API returns a non-success status code (that is, 4xx or 5xx\nresponse), a subclass of `writerai.APIStatusError` is raised, containing `status_code` and `response` properties.\n\nAll errors inherit from `writerai.APIError`.\n\n```python\nimport writerai\nfrom writerai import Writer\n\nclient = Writer()\n\ntry:\n client.chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n )\nexcept writerai.APIConnectionError as e:\n print("The server could not be reached")\n print(e.__cause__) # an underlying Exception, likely raised within httpx.\nexcept writerai.RateLimitError as e:\n print("A 429 status code was received; we should back off a bit.")\nexcept writerai.APIStatusError as e:\n print("Another non-200-range status code was received")\n print(e.status_code)\n print(e.response)\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors are automatically retried 7 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors are all retried by default.\n\nYou can use the `max_retries` option to configure or disable retry settings:\n\n```python\nfrom writerai import Writer\n\n# Configure the default for all requests:\nclient = Writer(\n # default is 2\n max_retries=0,\n)\n\n# Or, configure per-request:\nclient.with_options(max_retries = 5).chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\n```\n\n### Timeouts\n\nBy default requests time out after 3 minutes. You can configure this with a `timeout` option,\nwhich accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:\n\n```python\nfrom writerai import Writer\n\n# Configure the default for all requests:\nclient = Writer(\n # 20 seconds (default is 3 minutes)\n timeout=20.0,\n)\n\n# More granular control:\nclient = Writer(\n timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),\n)\n\n# Override per-request:\nclient.with_options(timeout = 5.0).chat.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\n```\n\nOn timeout, an `APITimeoutError` is thrown.\n\nNote that requests that time out are [retried twice by default](#retries).\n\n\n\n## Advanced\n\n### Logging\n\nWe use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.\n\nYou can enable logging by setting the environment variable `WRITER_LOG` to `info`.\n\n```shell\n$ export WRITER_LOG=info\n```\n\nOr to `debug` for more verbose logging.\n\n### How to tell whether `None` means `null` or missing\n\nIn an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:\n\n```py\nif response.my_field is None:\n if \'my_field\' not in response.model_fields_set:\n print(\'Got json like {}, without a "my_field" key present at all.\')\n else:\n print(\'Got json like {"my_field": null}.\')\n```\n\n### Accessing raw response data (e.g. headers)\n\nThe "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,\n\n```py\nfrom writerai import Writer\n\nclient = Writer()\nresponse = client.chat.with_raw_response.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n)\nprint(response.headers.get(\'X-My-Header\'))\n\nchat = response.parse() # get the object that `chat.chat()` would have returned\nprint(chat.id)\n```\n\nThese methods return an [`APIResponse`](https://github.com/writer/writer-python/tree/main/src/writerai/_response.py) object.\n\nThe async client returns an [`AsyncAPIResponse`](https://github.com/writer/writer-python/tree/main/src/writerai/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.\n\n#### `.with_streaming_response`\n\nThe above interface eagerly reads the full response body when you make the request, which may not always be what you want.\n\nTo stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.\n\n```python\nwith client.chat.with_streaming_response.chat(\n messages=[{\n "content": "Write a haiku about programming",\n "role": "user",\n }],\n model="palmyra-x5",\n) as response :\n print(response.headers.get(\'X-My-Header\'))\n\n for line in response.iter_lines():\n print(line)\n```\n\nThe context manager is required so that the response will reliably be closed.\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API.\n\nIf you need to access undocumented endpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other\nhttp verbs. Options on the client will be respected (such as retries) when making this request.\n\n```py\nimport httpx\n\nresponse = client.post(\n "/foo",\n cast_to=httpx.Response,\n body={"my_param": True},\n)\n\nprint(response.headers.get("x-foo"))\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You\ncan also get all the extra fields on the Pydantic model as a dict with\n[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).\n\n### Configuring the HTTP client\n\nYou can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:\n\n- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)\n- Custom [transports](https://www.python-httpx.org/advanced/transports/)\n- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality\n\n```python\nimport httpx\nfrom writerai import Writer, DefaultHttpxClient\n\nclient = Writer(\n # Or use the `WRITER_BASE_URL` env var\n base_url="http://my.test.server.example.com:8083",\n http_client=DefaultHttpxClient(proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0")),\n)\n```\n\nYou can also customize the client on a per-request basis by using `with_options()`:\n\n```python\nclient.with_options(http_client=DefaultHttpxClient(...))\n```\n\n### Managing HTTP resources\n\nBy default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.\n\n```py\nfrom writerai import Writer\n\nwith Writer() as client:\n # make requests here\n ...\n\n# HTTP client is now closed\n```\n\n## Versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/writer/writer-python/issues) with questions, bugs, or suggestions.\n\n### Determining the installed version\n\nIf you\'ve upgraded to the latest version but aren\'t seeing any new features you were expecting then your python environment is likely still using an older version.\n\nYou can determine the version that is being used at runtime with:\n\n```py\nimport writerai\nprint(writerai.__version__)\n```\n\n## Requirements\n\nPython 3.9 or higher.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n', }, { - "language": "typescript", - "content": "# Writer TypeScript API Library\n\n[![NPM version](https://img.shields.io/npm/v/writer-sdk.svg?label=npm%20(stable))](https://npmjs.org/package/writer-sdk) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/writer-sdk)\n\nThis library provides convenient access to the Writer REST API from server-side TypeScript or JavaScript.\n\n\n\nThe REST API documentation can be found on [dev.writer.com](https://dev.writer.com/api-guides/introduction). The full API of this library can be found in [api.md](api.md).\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n```sh\nnpm install writer-sdk\n```\n\n\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n\n```js\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst chatCompletion = await client.chat.chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n});\n\nconsole.log(chatCompletion.id);\n```\n\n## Streaming responses\n\nWe provide support for streaming responses using Server Sent Events (SSE).\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.chat.chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n stream: true,\n});\nfor await (const chatCompletionChunk of stream) {\n console.log(chatCompletionChunk.id);\n}\n```\n\nIf you need to cancel a stream, you can `break` from the loop\nor call `stream.controller.abort()`.\n\n### Request & Response types\n\nThis library includes TypeScript definitions for all request params and response fields. You may import and use them like so:\n\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst params: Writer.ChatChatParams = {\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n};\nconst chatCompletion: Writer.ChatCompletion = await client.chat.chat(params);\n```\n\nDocumentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.\n\n\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API,\nor if the API returns a non-success status code (i.e., 4xx or 5xx response),\na subclass of `APIError` will be thrown:\n\n\n```ts\nconst chatCompletion = await client.chat\n .chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n })\n .catch(async (err) => {\n if (err instanceof Writer.APIError) {\n console.log(err.status); // 400\n console.log(err.name); // BadRequestError\n console.log(err.headers); // {server: 'nginx', ...}\n } else {\n throw err;\n }\n });\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors will be automatically retried 7 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors will all be retried by default.\n\nYou can use the `maxRetries` option to configure or disable this:\n\n\n```js\n// Configure the default for all requests:\nconst client = new Writer({\n maxRetries: 0, // default is 2\n});\n\n// Or, configure per-request:\nawait client.chat.chat({ messages: [{ content: 'Write a haiku about programming', role: 'user' }], model: 'palmyra-x5' }, {\n maxRetries: 5,\n});\n```\n\n### Timeouts\n\nRequests time out after 3 minutes by default. You can configure this with a `timeout` option:\n\n\n```ts\n// Configure the default for all requests:\nconst client = new Writer({\n timeout: 20 * 1000, // 20 seconds (default is 3 minutes)\n});\n\n// Override per-request:\nawait client.chat.chat({ messages: [{ content: 'Write a haiku about programming', role: 'user' }], model: 'palmyra-x5' }, {\n timeout: 5 * 1000,\n});\n```\n\nOn timeout, an `APIConnectionTimeoutError` is thrown.\n\nNote that requests which time out will be [retried twice by default](#retries).\n\n## Auto-pagination\n\nList methods in the Writer API are paginated.\nYou can use the `for await … of` syntax to iterate through items across all pages:\n\n```ts\nasync function fetchAllGraphs(params) {\n const allGraphs = [];\n // Automatically fetches more pages as needed.\n for await (const graph of client.graphs.list()) {\n allGraphs.push(graph);\n }\n return allGraphs;\n}\n```\n\nAlternatively, you can request a single page at a time:\n\n```ts\nlet page = await client.graphs.list();\nfor (const graph of page.data) {\n console.log(graph);\n}\n\n// Convenience methods are provided for manually paginating:\nwhile (page.hasNextPage()) {\n page = await page.getNextPage();\n // ...\n}\n```\n\n\n\n## Advanced Usage\n\n### Accessing raw Response data (e.g., headers)\n\nThe \"raw\" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return.\nThis method returns as soon as the headers for a successful response are received and does not consume the response body, so you are free to write custom parsing or streaming logic.\n\nYou can also use the `.withResponse()` method to get the raw `Response` along with the parsed data.\nUnlike `.asResponse()` this method consumes the body, returning once it is parsed.\n\n\n```ts\nconst client = new Writer();\n\nconst response = await client.chat\n .chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n })\n .asResponse();\nconsole.log(response.headers.get('X-My-Header'));\nconsole.log(response.statusText); // access the underlying Response object\n\nconst { data: chatCompletion, response: raw } = await client.chat\n .chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n })\n .withResponse();\nconsole.log(raw.headers.get('X-My-Header'));\nconsole.log(chatCompletion.id);\n```\n\n### Logging\n\n> [!IMPORTANT]\n> All log messages are intended for debugging only. The format and content of log messages\n> may change between releases.\n\n#### Log levels\n\nThe log level can be configured in two ways:\n\n1. Via the `WRITER_LOG` environment variable\n2. Using the `logLevel` client option (overrides the environment variable if set)\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n logLevel: 'debug', // Show all log messages\n});\n```\n\nAvailable log levels, from most to least verbose:\n\n- `'debug'` - Show debug messages, info, warnings, and errors\n- `'info'` - Show info messages, warnings, and errors\n- `'warn'` - Show warnings and errors (default)\n- `'error'` - Show only errors\n- `'off'` - Disable all logging\n\nAt the `'debug'` level, all HTTP requests and responses are logged, including headers and bodies.\nSome authentication-related headers are redacted, but sensitive data in request and response bodies\nmay still be visible.\n\n#### Custom logger\n\nBy default, this library logs to `globalThis.console`. You can also provide a custom logger.\nMost logging libraries are supported, including [pino](https://www.npmjs.com/package/pino), [winston](https://www.npmjs.com/package/winston), [bunyan](https://www.npmjs.com/package/bunyan), [consola](https://www.npmjs.com/package/consola), [signale](https://www.npmjs.com/package/signale), and [@std/log](https://jsr.io/@std/log). If your logger doesn't work, please open an issue.\n\nWhen providing a custom logger, the `logLevel` option still controls which messages are emitted, messages\nbelow the configured level will not be sent to your logger.\n\n```ts\nimport Writer from 'writer-sdk';\nimport pino from 'pino';\n\nconst logger = pino();\n\nconst client = new Writer({\n logger: logger.child({ name: 'Writer' }),\n logLevel: 'debug', // Send all messages to pino, allowing it to filter\n});\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs.\nOptions on the client, such as retries, will be respected when making these requests.\n\n```ts\nawait client.post('/some/path', {\n body: { some_prop: 'foo' },\n query: { some_query_arg: 'bar' },\n});\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented\nparameter. This library doesn't validate at runtime that the request matches the type, so any extra values you\nsend will be sent as-is.\n\n```ts\nclient.chat.chat({\n // ...\n // @ts-expect-error baz is not yet public\n baz: 'undocumented option',\n});\n```\n\nFor requests with the `GET` verb, any extra params will be in the query, all other requests will send the\nextra param in the body.\n\nIf you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may access the response object with `// @ts-expect-error` on\nthe response object, or cast the response object to the requisite type. Like the request params, we do not\nvalidate or strip extra properties from the response from the API.\n\n### Customizing the fetch client\n\nBy default, this library expects a global `fetch` function is defined.\n\nIf you want to use a different `fetch` function, you can either polyfill the global:\n\n```ts\nimport fetch from 'my-fetch';\n\nglobalThis.fetch = fetch;\n```\n\nOr pass it to the client:\n\n```ts\nimport Writer from 'writer-sdk';\nimport fetch from 'my-fetch';\n\nconst client = new Writer({ fetch });\n```\n\n### Fetch options\n\nIf you want to set custom `fetch` options without overriding the `fetch` function, you can provide a `fetchOptions` object when instantiating the client or making a request. (Request-specific options override client options.)\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n fetchOptions: {\n // `RequestInit` options\n },\n});\n```\n\n#### Configuring proxies\n\nTo modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy\noptions to requests:\n\n **Node** [[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)]\n\n```ts\nimport Writer from 'writer-sdk';\nimport * as undici from 'undici';\n\nconst proxyAgent = new undici.ProxyAgent('http://localhost:8888');\nconst client = new Writer({\n fetchOptions: {\n dispatcher: proxyAgent,\n },\n});\n```\n\n **Bun** [[docs](https://bun.sh/guides/http/proxy)]\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n fetchOptions: {\n proxy: 'http://localhost:8888',\n },\n});\n```\n\n **Deno** [[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)]\n\n```ts\nimport Writer from 'npm:writer-sdk';\n\nconst httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });\nconst client = new Writer({\n fetchOptions: {\n client: httpClient,\n },\n});\n```\n\n## Frequently Asked Questions\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/writer/writer-node/issues) with questions, bugs, or suggestions.\n\n## Requirements\n\nTypeScript >= 4.9 is supported.\n\nThe following runtimes are supported:\n\n- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more)\n- Node.js 20 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions.\n- Deno v1.28.0 or higher.\n- Bun 1.0 or later.\n- Cloudflare Workers.\n- Vercel Edge Runtime.\n- Jest 28 or greater with the `\"node\"` environment (`\"jsdom\"` is not supported at this time).\n- Nitro v2.6 or greater.\n\nNote that React Native is not supported at this time.\n\nIf you are interested in other runtime environments, please open or upvote an issue on GitHub.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n" - } + language: 'typescript', + content: + "# Writer TypeScript API Library\n\n[![NPM version](https://img.shields.io/npm/v/writer-sdk.svg?label=npm%20(stable))](https://npmjs.org/package/writer-sdk) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/writer-sdk)\n\nThis library provides convenient access to the Writer REST API from server-side TypeScript or JavaScript.\n\n\n\nThe REST API documentation can be found on [dev.writer.com](https://dev.writer.com/api-guides/introduction). The full API of this library can be found in [api.md](api.md).\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Writer MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=writer-sdk-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIndyaXRlci1zZGstbWNwIl0sImVudiI6eyJXUklURVJfQVBJX0tFWSI6Ik15IEFQSSBLZXkifX0)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22writer-sdk-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22writer-sdk-mcp%22%5D%2C%22env%22%3A%7B%22WRITER_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n```sh\nnpm install writer-sdk\n```\n\n\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n\n```js\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst chatCompletion = await client.chat.chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n});\n\nconsole.log(chatCompletion.id);\n```\n\n## Streaming responses\n\nWe provide support for streaming responses using Server Sent Events (SSE).\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst stream = await client.chat.chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n stream: true,\n});\nfor await (const chatCompletionChunk of stream) {\n console.log(chatCompletionChunk.id);\n}\n```\n\nIf you need to cancel a stream, you can `break` from the loop\nor call `stream.controller.abort()`.\n\n### Request & Response types\n\nThis library includes TypeScript definitions for all request params and response fields. You may import and use them like so:\n\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst params: Writer.ChatChatParams = {\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n};\nconst chatCompletion: Writer.ChatCompletion = await client.chat.chat(params);\n```\n\nDocumentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.\n\n\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API,\nor if the API returns a non-success status code (i.e., 4xx or 5xx response),\na subclass of `APIError` will be thrown:\n\n\n```ts\nconst chatCompletion = await client.chat\n .chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n })\n .catch(async (err) => {\n if (err instanceof Writer.APIError) {\n console.log(err.status); // 400\n console.log(err.name); // BadRequestError\n console.log(err.headers); // {server: 'nginx', ...}\n } else {\n throw err;\n }\n });\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors will be automatically retried 7 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors will all be retried by default.\n\nYou can use the `maxRetries` option to configure or disable this:\n\n\n```js\n// Configure the default for all requests:\nconst client = new Writer({\n maxRetries: 0, // default is 2\n});\n\n// Or, configure per-request:\nawait client.chat.chat({ messages: [{ content: 'Write a haiku about programming', role: 'user' }], model: 'palmyra-x5' }, {\n maxRetries: 5,\n});\n```\n\n### Timeouts\n\nRequests time out after 3 minutes by default. You can configure this with a `timeout` option:\n\n\n```ts\n// Configure the default for all requests:\nconst client = new Writer({\n timeout: 20 * 1000, // 20 seconds (default is 3 minutes)\n});\n\n// Override per-request:\nawait client.chat.chat({ messages: [{ content: 'Write a haiku about programming', role: 'user' }], model: 'palmyra-x5' }, {\n timeout: 5 * 1000,\n});\n```\n\nOn timeout, an `APIConnectionTimeoutError` is thrown.\n\nNote that requests which time out will be [retried twice by default](#retries).\n\n## Auto-pagination\n\nList methods in the Writer API are paginated.\nYou can use the `for await … of` syntax to iterate through items across all pages:\n\n```ts\nasync function fetchAllGraphs(params) {\n const allGraphs = [];\n // Automatically fetches more pages as needed.\n for await (const graph of client.graphs.list()) {\n allGraphs.push(graph);\n }\n return allGraphs;\n}\n```\n\nAlternatively, you can request a single page at a time:\n\n```ts\nlet page = await client.graphs.list();\nfor (const graph of page.data) {\n console.log(graph);\n}\n\n// Convenience methods are provided for manually paginating:\nwhile (page.hasNextPage()) {\n page = await page.getNextPage();\n // ...\n}\n```\n\n\n\n## Advanced Usage\n\n### Accessing raw Response data (e.g., headers)\n\nThe \"raw\" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return.\nThis method returns as soon as the headers for a successful response are received and does not consume the response body, so you are free to write custom parsing or streaming logic.\n\nYou can also use the `.withResponse()` method to get the raw `Response` along with the parsed data.\nUnlike `.asResponse()` this method consumes the body, returning once it is parsed.\n\n\n```ts\nconst client = new Writer();\n\nconst response = await client.chat\n .chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n })\n .asResponse();\nconsole.log(response.headers.get('X-My-Header'));\nconsole.log(response.statusText); // access the underlying Response object\n\nconst { data: chatCompletion, response: raw } = await client.chat\n .chat({\n messages: [{ content: 'Write a haiku about programming', role: 'user' }],\n model: 'palmyra-x5',\n })\n .withResponse();\nconsole.log(raw.headers.get('X-My-Header'));\nconsole.log(chatCompletion.id);\n```\n\n### Logging\n\n> [!IMPORTANT]\n> All log messages are intended for debugging only. The format and content of log messages\n> may change between releases.\n\n#### Log levels\n\nThe log level can be configured in two ways:\n\n1. Via the `WRITER_LOG` environment variable\n2. Using the `logLevel` client option (overrides the environment variable if set)\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n logLevel: 'debug', // Show all log messages\n});\n```\n\nAvailable log levels, from most to least verbose:\n\n- `'debug'` - Show debug messages, info, warnings, and errors\n- `'info'` - Show info messages, warnings, and errors\n- `'warn'` - Show warnings and errors (default)\n- `'error'` - Show only errors\n- `'off'` - Disable all logging\n\nAt the `'debug'` level, all HTTP requests and responses are logged, including headers and bodies.\nSome authentication-related headers are redacted, but sensitive data in request and response bodies\nmay still be visible.\n\n#### Custom logger\n\nBy default, this library logs to `globalThis.console`. You can also provide a custom logger.\nMost logging libraries are supported, including [pino](https://www.npmjs.com/package/pino), [winston](https://www.npmjs.com/package/winston), [bunyan](https://www.npmjs.com/package/bunyan), [consola](https://www.npmjs.com/package/consola), [signale](https://www.npmjs.com/package/signale), and [@std/log](https://jsr.io/@std/log). If your logger doesn't work, please open an issue.\n\nWhen providing a custom logger, the `logLevel` option still controls which messages are emitted, messages\nbelow the configured level will not be sent to your logger.\n\n```ts\nimport Writer from 'writer-sdk';\nimport pino from 'pino';\n\nconst logger = pino();\n\nconst client = new Writer({\n logger: logger.child({ name: 'Writer' }),\n logLevel: 'debug', // Send all messages to pino, allowing it to filter\n});\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs.\nOptions on the client, such as retries, will be respected when making these requests.\n\n```ts\nawait client.post('/some/path', {\n body: { some_prop: 'foo' },\n query: { some_query_arg: 'bar' },\n});\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented\nparameter. This library doesn't validate at runtime that the request matches the type, so any extra values you\nsend will be sent as-is.\n\n```ts\nclient.chat.chat({\n // ...\n // @ts-expect-error baz is not yet public\n baz: 'undocumented option',\n});\n```\n\nFor requests with the `GET` verb, any extra params will be in the query, all other requests will send the\nextra param in the body.\n\nIf you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may access the response object with `// @ts-expect-error` on\nthe response object, or cast the response object to the requisite type. Like the request params, we do not\nvalidate or strip extra properties from the response from the API.\n\n### Customizing the fetch client\n\nBy default, this library expects a global `fetch` function is defined.\n\nIf you want to use a different `fetch` function, you can either polyfill the global:\n\n```ts\nimport fetch from 'my-fetch';\n\nglobalThis.fetch = fetch;\n```\n\nOr pass it to the client:\n\n```ts\nimport Writer from 'writer-sdk';\nimport fetch from 'my-fetch';\n\nconst client = new Writer({ fetch });\n```\n\n### Fetch options\n\nIf you want to set custom `fetch` options without overriding the `fetch` function, you can provide a `fetchOptions` object when instantiating the client or making a request. (Request-specific options override client options.)\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n fetchOptions: {\n // `RequestInit` options\n },\n});\n```\n\n#### Configuring proxies\n\nTo modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy\noptions to requests:\n\n **Node** [[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)]\n\n```ts\nimport Writer from 'writer-sdk';\nimport * as undici from 'undici';\n\nconst proxyAgent = new undici.ProxyAgent('http://localhost:8888');\nconst client = new Writer({\n fetchOptions: {\n dispatcher: proxyAgent,\n },\n});\n```\n\n **Bun** [[docs](https://bun.sh/guides/http/proxy)]\n\n```ts\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n fetchOptions: {\n proxy: 'http://localhost:8888',\n },\n});\n```\n\n **Deno** [[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)]\n\n```ts\nimport Writer from 'npm:writer-sdk';\n\nconst httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });\nconst client = new Writer({\n fetchOptions: {\n client: httpClient,\n },\n});\n```\n\n## Frequently Asked Questions\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/writer/writer-node/issues) with questions, bugs, or suggestions.\n\n## Requirements\n\nTypeScript >= 4.9 is supported.\n\nThe following runtimes are supported:\n\n- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more)\n- Node.js 20 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions.\n- Deno v1.28.0 or higher.\n- Bun 1.0 or later.\n- Cloudflare Workers.\n- Vercel Edge Runtime.\n- Jest 28 or greater with the `\"node\"` environment (`\"jsdom\"` is not supported at this time).\n- Nitro v2.6 or greater.\n\nNote that React Native is not supported at this time.\n\nIf you are interested in other runtime environments, please open or upvote an issue on GitHub.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n", + }, ]; const INDEX_OPTIONS = { @@ -1127,21 +1252,18 @@ export class LocalDocsSearch { maxResults?: number; maxLength?: number; }): SearchResult { - const { - query, - language = 'typescript', - detail = 'default', - maxResults = 5, - maxLength = 100_000, - } = props; + const { query, language = 'typescript', detail = 'default', maxResults = 5, maxLength = 100_000 } = props; const useMarkdown = detail === 'verbose' || detail === 'high'; // Search both indices and merge results by score. // Filter prose hits so language-tagged content (READMEs and docs with // frontmatter) only matches the requested language. - const methodHits = this.methodIndex.search(query).map((hit) => ({ ...hit, _kind: 'http_method' as const })); - const proseHits = this.proseIndex.search(query) + const methodHits = this.methodIndex + .search(query) + .map((hit) => ({ ...hit, _kind: 'http_method' as const })); + const proseHits = this.proseIndex + .search(query) .filter((hit) => { const source = ((hit as Record)['_original'] as ProseChunk | undefined)?.source; if (!source) return true; diff --git a/packages/mcp-server/src/methods.ts b/packages/mcp-server/src/methods.ts index 9cb7f919..c20ca99b 100644 --- a/packages/mcp-server/src/methods.ts +++ b/packages/mcp-server/src/methods.ts @@ -7,159 +7,190 @@ export type SdkMethod = { fullyQualifiedName: string; httpMethod?: 'get' | 'post' | 'put' | 'patch' | 'delete' | 'query'; httpPath?: string; -} +}; -export const sdkMethods: SdkMethod[] = [{ - clientCallName: 'client.applications.retrieve', - fullyQualifiedName: 'applications.retrieve', - httpMethod: 'get', - httpPath: '/v1/applications/{application_id}', -},{ - clientCallName: 'client.applications.list', - fullyQualifiedName: 'applications.list', - httpMethod: 'get', - httpPath: '/v1/applications', -},{ - clientCallName: 'client.applications.generateContent', - fullyQualifiedName: 'applications.generateContent', - httpMethod: 'post', - httpPath: '/v1/applications/{application_id}', -},{ - clientCallName: 'client.applications.jobs.create', - fullyQualifiedName: 'applications.jobs.create', - httpMethod: 'post', - httpPath: '/v1/applications/{application_id}/jobs', -},{ - clientCallName: 'client.applications.jobs.retrieve', - fullyQualifiedName: 'applications.jobs.retrieve', - httpMethod: 'get', - httpPath: '/v1/applications/jobs/{job_id}', -},{ - clientCallName: 'client.applications.jobs.list', - fullyQualifiedName: 'applications.jobs.list', - httpMethod: 'get', - httpPath: '/v1/applications/{application_id}/jobs', -},{ - clientCallName: 'client.applications.jobs.retry', - fullyQualifiedName: 'applications.jobs.retry', - httpMethod: 'post', - httpPath: '/v1/applications/jobs/{job_id}/retry', -},{ - clientCallName: 'client.applications.graphs.update', - fullyQualifiedName: 'applications.graphs.update', - httpMethod: 'put', - httpPath: '/v1/applications/{application_id}/graphs', -},{ - clientCallName: 'client.applications.graphs.list', - fullyQualifiedName: 'applications.graphs.list', - httpMethod: 'get', - httpPath: '/v1/applications/{application_id}/graphs', -},{ - clientCallName: 'client.chat.chat', - fullyQualifiedName: 'chat.chat', - httpMethod: 'post', - httpPath: '/v1/chat', -},{ - clientCallName: 'client.completions.create', - fullyQualifiedName: 'completions.create', - httpMethod: 'post', - httpPath: '/v1/completions', -},{ - clientCallName: 'client.models.list', - fullyQualifiedName: 'models.list', - httpMethod: 'get', - httpPath: '/v1/models', -},{ - clientCallName: 'client.graphs.create', - fullyQualifiedName: 'graphs.create', - httpMethod: 'post', - httpPath: '/v1/graphs', -},{ - clientCallName: 'client.graphs.retrieve', - fullyQualifiedName: 'graphs.retrieve', - httpMethod: 'get', - httpPath: '/v1/graphs/{graph_id}', -},{ - clientCallName: 'client.graphs.update', - fullyQualifiedName: 'graphs.update', - httpMethod: 'put', - httpPath: '/v1/graphs/{graph_id}', -},{ - clientCallName: 'client.graphs.list', - fullyQualifiedName: 'graphs.list', - httpMethod: 'get', - httpPath: '/v1/graphs', -},{ - clientCallName: 'client.graphs.delete', - fullyQualifiedName: 'graphs.delete', - httpMethod: 'delete', - httpPath: '/v1/graphs/{graph_id}', -},{ - clientCallName: 'client.graphs.addFileToGraph', - fullyQualifiedName: 'graphs.addFileToGraph', - httpMethod: 'post', - httpPath: '/v1/graphs/{graph_id}/file', -},{ - clientCallName: 'client.graphs.question', - fullyQualifiedName: 'graphs.question', - httpMethod: 'post', - httpPath: '/v1/graphs/question', -},{ - clientCallName: 'client.graphs.removeFileFromGraph', - fullyQualifiedName: 'graphs.removeFileFromGraph', - httpMethod: 'delete', - httpPath: '/v1/graphs/{graph_id}/file/{file_id}', -},{ - clientCallName: 'client.files.retrieve', - fullyQualifiedName: 'files.retrieve', - httpMethod: 'get', - httpPath: '/v1/files/{file_id}', -},{ - clientCallName: 'client.files.list', - fullyQualifiedName: 'files.list', - httpMethod: 'get', - httpPath: '/v1/files', -},{ - clientCallName: 'client.files.delete', - fullyQualifiedName: 'files.delete', - httpMethod: 'delete', - httpPath: '/v1/files/{file_id}', -},{ - clientCallName: 'client.files.download', - fullyQualifiedName: 'files.download', - httpMethod: 'get', - httpPath: '/v1/files/{file_id}/download', -},{ - clientCallName: 'client.files.retry', - fullyQualifiedName: 'files.retry', - httpMethod: 'post', - httpPath: '/v1/files/retry', -},{ - clientCallName: 'client.files.upload', - fullyQualifiedName: 'files.upload', - httpMethod: 'post', - httpPath: '/v1/files', -},{ - clientCallName: 'client.tools.parsePdf', - fullyQualifiedName: 'tools.parsePdf', - httpMethod: 'post', - httpPath: '/v1/tools/pdf-parser/{file_id}', -},{ - clientCallName: 'client.tools.webSearch', - fullyQualifiedName: 'tools.webSearch', - httpMethod: 'post', - httpPath: '/v1/tools/web-search', -},{ - clientCallName: 'client.translation.translate', - fullyQualifiedName: 'translation.translate', - httpMethod: 'post', - httpPath: '/v1/translation', -},{ - clientCallName: 'client.vision.analyze', - fullyQualifiedName: 'vision.analyze', - httpMethod: 'post', - httpPath: '/v1/vision', -}]; +export const sdkMethods: SdkMethod[] = [ + { + clientCallName: 'client.applications.retrieve', + fullyQualifiedName: 'applications.retrieve', + httpMethod: 'get', + httpPath: '/v1/applications/{application_id}', + }, + { + clientCallName: 'client.applications.list', + fullyQualifiedName: 'applications.list', + httpMethod: 'get', + httpPath: '/v1/applications', + }, + { + clientCallName: 'client.applications.generateContent', + fullyQualifiedName: 'applications.generateContent', + httpMethod: 'post', + httpPath: '/v1/applications/{application_id}', + }, + { + clientCallName: 'client.applications.jobs.create', + fullyQualifiedName: 'applications.jobs.create', + httpMethod: 'post', + httpPath: '/v1/applications/{application_id}/jobs', + }, + { + clientCallName: 'client.applications.jobs.retrieve', + fullyQualifiedName: 'applications.jobs.retrieve', + httpMethod: 'get', + httpPath: '/v1/applications/jobs/{job_id}', + }, + { + clientCallName: 'client.applications.jobs.list', + fullyQualifiedName: 'applications.jobs.list', + httpMethod: 'get', + httpPath: '/v1/applications/{application_id}/jobs', + }, + { + clientCallName: 'client.applications.jobs.retry', + fullyQualifiedName: 'applications.jobs.retry', + httpMethod: 'post', + httpPath: '/v1/applications/jobs/{job_id}/retry', + }, + { + clientCallName: 'client.applications.graphs.update', + fullyQualifiedName: 'applications.graphs.update', + httpMethod: 'put', + httpPath: '/v1/applications/{application_id}/graphs', + }, + { + clientCallName: 'client.applications.graphs.list', + fullyQualifiedName: 'applications.graphs.list', + httpMethod: 'get', + httpPath: '/v1/applications/{application_id}/graphs', + }, + { + clientCallName: 'client.chat.chat', + fullyQualifiedName: 'chat.chat', + httpMethod: 'post', + httpPath: '/v1/chat', + }, + { + clientCallName: 'client.completions.create', + fullyQualifiedName: 'completions.create', + httpMethod: 'post', + httpPath: '/v1/completions', + }, + { + clientCallName: 'client.models.list', + fullyQualifiedName: 'models.list', + httpMethod: 'get', + httpPath: '/v1/models', + }, + { + clientCallName: 'client.graphs.create', + fullyQualifiedName: 'graphs.create', + httpMethod: 'post', + httpPath: '/v1/graphs', + }, + { + clientCallName: 'client.graphs.retrieve', + fullyQualifiedName: 'graphs.retrieve', + httpMethod: 'get', + httpPath: '/v1/graphs/{graph_id}', + }, + { + clientCallName: 'client.graphs.update', + fullyQualifiedName: 'graphs.update', + httpMethod: 'put', + httpPath: '/v1/graphs/{graph_id}', + }, + { + clientCallName: 'client.graphs.list', + fullyQualifiedName: 'graphs.list', + httpMethod: 'get', + httpPath: '/v1/graphs', + }, + { + clientCallName: 'client.graphs.delete', + fullyQualifiedName: 'graphs.delete', + httpMethod: 'delete', + httpPath: '/v1/graphs/{graph_id}', + }, + { + clientCallName: 'client.graphs.addFileToGraph', + fullyQualifiedName: 'graphs.addFileToGraph', + httpMethod: 'post', + httpPath: '/v1/graphs/{graph_id}/file', + }, + { + clientCallName: 'client.graphs.question', + fullyQualifiedName: 'graphs.question', + httpMethod: 'post', + httpPath: '/v1/graphs/question', + }, + { + clientCallName: 'client.graphs.removeFileFromGraph', + fullyQualifiedName: 'graphs.removeFileFromGraph', + httpMethod: 'delete', + httpPath: '/v1/graphs/{graph_id}/file/{file_id}', + }, + { + clientCallName: 'client.files.retrieve', + fullyQualifiedName: 'files.retrieve', + httpMethod: 'get', + httpPath: '/v1/files/{file_id}', + }, + { + clientCallName: 'client.files.list', + fullyQualifiedName: 'files.list', + httpMethod: 'get', + httpPath: '/v1/files', + }, + { + clientCallName: 'client.files.delete', + fullyQualifiedName: 'files.delete', + httpMethod: 'delete', + httpPath: '/v1/files/{file_id}', + }, + { + clientCallName: 'client.files.download', + fullyQualifiedName: 'files.download', + httpMethod: 'get', + httpPath: '/v1/files/{file_id}/download', + }, + { + clientCallName: 'client.files.retry', + fullyQualifiedName: 'files.retry', + httpMethod: 'post', + httpPath: '/v1/files/retry', + }, + { + clientCallName: 'client.files.upload', + fullyQualifiedName: 'files.upload', + httpMethod: 'post', + httpPath: '/v1/files', + }, + { + clientCallName: 'client.tools.parsePdf', + fullyQualifiedName: 'tools.parsePdf', + httpMethod: 'post', + httpPath: '/v1/tools/pdf-parser/{file_id}', + }, + { + clientCallName: 'client.tools.webSearch', + fullyQualifiedName: 'tools.webSearch', + httpMethod: 'post', + httpPath: '/v1/tools/web-search', + }, + { + clientCallName: 'client.translation.translate', + fullyQualifiedName: 'translation.translate', + httpMethod: 'post', + httpPath: '/v1/translation', + }, + { + clientCallName: 'client.vision.analyze', + fullyQualifiedName: 'vision.analyze', + httpMethod: 'post', + httpPath: '/v1/vision', + }, +]; function allowedMethodsForCodeTool(options: McpOptions | undefined): SdkMethod[] | undefined { if (!options) { @@ -174,9 +205,9 @@ function allowedMethodsForCodeTool(options: McpOptions | undefined): SdkMethod[] if (options.codeAllowHttpGets) { // Add all methods that map to an HTTP GET - sdkMethods.filter((method) => method.httpMethod === 'get').forEach( - (method) => allowedMethodsSet.add(method) - ); + sdkMethods + .filter((method) => method.httpMethod === 'get') + .forEach((method) => allowedMethodsSet.add(method)); } if (options.codeAllowedMethods) { @@ -185,13 +216,15 @@ function allowedMethodsForCodeTool(options: McpOptions | undefined): SdkMethod[] try { return new RegExp(pattern); } catch (e) { - throw new Error(`Invalid regex pattern for allowed method: "${pattern}": ${e instanceof Error ? e.message : e}`); + throw new Error( + `Invalid regex pattern for allowed method: "${pattern}": ${e instanceof Error ? e.message : e}`, + ); } }); - sdkMethods.filter((method) => - allowedRegexps.some((regexp) => regexp.test(method.fullyQualifiedName)) - ).forEach((method) => allowedMethodsSet.add(method)); + sdkMethods + .filter((method) => allowedRegexps.some((regexp) => regexp.test(method.fullyQualifiedName))) + .forEach((method) => allowedMethodsSet.add(method)); } allowedMethods = Array.from(allowedMethodsSet); @@ -206,12 +239,14 @@ function allowedMethodsForCodeTool(options: McpOptions | undefined): SdkMethod[] try { return new RegExp(pattern); } catch (e) { - throw new Error(`Invalid regex pattern for blocked method: "${pattern}": ${e instanceof Error ? e.message : e}`); + throw new Error( + `Invalid regex pattern for blocked method: "${pattern}": ${e instanceof Error ? e.message : e}`, + ); } }); - allowedMethods = allowedMethods.filter((method) => - !blockedRegexps.some((regexp) => regexp.test(method.fullyQualifiedName)) + allowedMethods = allowedMethods.filter( + (method) => !blockedRegexps.some((regexp) => regexp.test(method.fullyQualifiedName)), ); } diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts index 873ab8e8..f1518764 100644 --- a/packages/mcp-server/src/options.ts +++ b/packages/mcp-server/src/options.ts @@ -31,31 +31,46 @@ export type McpCodeExecutionMode = 'stainless-sandbox' | 'local'; export function parseCLIOptions(): CLIOptions { const opts = yargs(hideBin(process.argv)) - .option('code-allow-http-gets', { type: 'boolean', description: 'Allow all code tool methods that map to HTTP GET operations. If all code-allow-* flags are unset, then everything is allowed.' }) + .option('code-allow-http-gets', { + type: 'boolean', + description: + 'Allow all code tool methods that map to HTTP GET operations. If all code-allow-* flags are unset, then everything is allowed.', + }) .option('code-allowed-methods', { type: 'string', array: true, - description: 'Methods to explicitly allow for code tool. Evaluated as regular expressions against method fully qualified names. If all code-allow-* flags are unset, then everything is allowed.', + description: + 'Methods to explicitly allow for code tool. Evaluated as regular expressions against method fully qualified names. If all code-allow-* flags are unset, then everything is allowed.', }) .option('code-blocked-methods', { type: 'string', array: true, - description: 'Methods to explicitly block for code tool. Evaluated as regular expressions against method fully qualified names. If all code-allow-* flags are unset, then everything is allowed.', + description: + 'Methods to explicitly block for code tool. Evaluated as regular expressions against method fully qualified names. If all code-allow-* flags are unset, then everything is allowed.', }) .option('code-execution-mode', { type: 'string', choices: ['stainless-sandbox', 'local'], default: 'stainless-sandbox', - description: 'Where to run code execution in code tool; \'stainless-sandbox\' will execute code in Stainless-hosted sandboxes whereas \'local\' will execute code locally on the MCP server machine.', + description: + "Where to run code execution in code tool; 'stainless-sandbox' will execute code in Stainless-hosted sandboxes whereas 'local' will execute code locally on the MCP server machine.", + }) + .option('custom-instructions-path', { + type: 'string', + description: 'Path to custom instructions for the MCP server', }) - .option('custom-instructions-path', { type: 'string', description: 'Path to custom instructions for the MCP server' }) .option('debug', { type: 'boolean', description: 'Enable debug logging' }) - .option('docs-dir', { type: 'string', description: 'Path to a directory of local documentation files (markdown/JSON) to include in local docs search.' }) + .option('docs-dir', { + type: 'string', + description: + 'Path to a directory of local documentation files (markdown/JSON) to include in local docs search.', + }) .option('docs-search-mode', { type: 'string', choices: ['stainless-api', 'local'], default: 'stainless-api', - description: 'Where to search documentation; \'stainless-api\' uses the Stainless-hosted search API whereas \'local\' uses an in-memory search index built from embedded SDK method data and optional local docs files.', + description: + "Where to search documentation; 'stainless-api' uses the Stainless-hosted search API whereas 'local' uses an in-memory search index built from embedded SDK method data and optional local docs files.", }) .option('log-format', { type: 'string', @@ -77,7 +92,8 @@ export function parseCLIOptions(): CLIOptions { .option('stainless-api-key', { type: 'string', default: readEnv('STAINLESS_API_KEY'), - description: 'API key for Stainless. Used to authenticate requests to Stainless-hosted tools endpoints.', + description: + 'API key for Stainless. Used to authenticate requests to Stainless-hosted tools endpoints.', }) .option('tools', { type: 'string', @@ -98,15 +114,18 @@ export function parseCLIOptions(): CLIOptions { const argv = opts.parseSync(); const shouldIncludeToolType = (toolType: 'code' | 'docs') => - argv.noTools?.includes(toolType) ? false - : argv.tools?.includes(toolType) ? true - : undefined; + argv.noTools?.includes(toolType) ? false + : argv.tools?.includes(toolType) ? true + : undefined; const includeCodeTool = shouldIncludeToolType('code'); const includeDocsTools = shouldIncludeToolType('docs'); const transport = argv.transport as 'stdio' | 'http'; - const logFormat = argv.logFormat ? argv.logFormat as 'json' | 'pretty' : (process.stderr.isTTY ? 'pretty' : 'json'); + const logFormat = + argv.logFormat ? (argv.logFormat as 'json' | 'pretty') + : process.stderr.isTTY ? 'pretty' + : 'json'; return { ...(includeCodeTool !== undefined && { includeCodeTool }), @@ -147,8 +166,8 @@ export function parseQueryOptions(defaultOptions: McpOptions, query: unknown): M const queryOptions = QueryOptions.parse(queryObject); let codeTool: boolean | undefined = - queryOptions.no_tools && queryOptions.no_tools?.includes("code") ? false - : queryOptions.tools?.includes("code") ? true + queryOptions.no_tools && queryOptions.no_tools?.includes('code') ? false + : queryOptions.tools?.includes('code') ? true : defaultOptions.includeCodeTool; let docsTools: boolean | undefined = diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index e2aa3207..f6b107b8 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -3,7 +3,9 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { - CallToolRequestSchema,ListToolsRequestSchema,SetLevelRequestSchema + CallToolRequestSchema, + ListToolsRequestSchema, + SetLevelRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { ClientOptions } from 'writer-sdk'; import Writer from 'writer-sdk'; @@ -14,24 +16,25 @@ import { LocalDocsSearch } from './local-docs-search'; import { getInstructions } from './instructions'; import { McpOptions } from './options'; import { blockedMethodsForCodeTool } from './methods'; -import { HandlerFunction, McpRequestContext, ToolCallResult, McpTool } from "./types" +import { HandlerFunction, McpRequestContext, ToolCallResult, McpTool } from './types'; export const newMcpServer = async ({ stainlessApiKey, customInstructionsPath, }: { - stainlessApiKey?: string | undefined, - customInstructionsPath?: string | undefined, -}) => new McpServer( - { - name: 'writer_sdk_api', - version: '3.0.0-rc.1', - }, - { - instructions: await getInstructions({stainlessApiKey, customInstructionsPath}), - capabilities: { tools: {}, logging: {} }, - } -); + stainlessApiKey?: string | undefined; + customInstructionsPath?: string | undefined; +}) => + new McpServer( + { + name: 'writer_sdk_api', + version: '3.0.0-rc.1', + }, + { + instructions: await getInstructions({ stainlessApiKey, customInstructionsPath }), + capabilities: { tools: {}, logging: {} }, + }, + ); /** * Initializes the provided MCP Server with the given tools and handlers. @@ -53,15 +56,15 @@ export async function initMcpServer(params: { (message: string, ...rest: unknown[]) => { void server.sendLoggingMessage({ level, - data: {message, rest}, + data: { message, rest }, }); - } + }; const logger = { - debug: logAtLevel("debug"), - info: logAtLevel("info"), - warn: logAtLevel("warning"), - error: logAtLevel("error"), - } + debug: logAtLevel('debug'), + info: logAtLevel('info'), + warn: logAtLevel('warning'), + error: logAtLevel('error'), + }; if (params.mcpOptions?.docsSearchMode === 'local') { const docsDir = params.mcpOptions?.docsDir; @@ -78,14 +81,13 @@ export async function initMcpServer(params: { if (!_client) { try { _client = new Writer({ - - logger, - ...params.clientOptions, - defaultHeaders: { - ...params.clientOptions?.defaultHeaders, - 'X-Stainless-MCP': 'true', - }, -}); + logger, + ...params.clientOptions, + defaultHeaders: { + ...params.clientOptions?.defaultHeaders, + 'X-Stainless-MCP': 'true', + }, + }); if (_logLevel) { _client = _client.withOptions({ logLevel: _logLevel }); } @@ -118,10 +120,12 @@ export async function initMcpServer(params: { client = getClient(); } catch (error) { return { - content: [{ - type: 'text' as const, - text: `Failed to initialize client: ${error instanceof Error ? error.message : String(error)}`, - }], + content: [ + { + type: 'text' as const, + text: `Failed to initialize client: ${error instanceof Error ? error.message : String(error)}`, + }, + ], isError: true, }; } @@ -171,17 +175,16 @@ export async function initMcpServer(params: { /** * Selects the tools to include in the MCP Server based on the provided options. */ -export function selectTools( - options?: McpOptions -): McpTool[] { - +export function selectTools(options?: McpOptions): McpTool[] { const includedTools = []; if (options?.includeCodeTool ?? true) { - includedTools.push(codeTool({ - blockedMethods: blockedMethodsForCodeTool(options), - codeExecutionMode: options?.codeExecutionMode ?? 'stainless-sandbox', - })); + includedTools.push( + codeTool({ + blockedMethods: blockedMethodsForCodeTool(options), + codeExecutionMode: options?.codeExecutionMode ?? 'stainless-sandbox', + }), + ); } if (options?.includeDocsTools ?? true) { includedTools.push(docsSearchTool); @@ -192,13 +195,14 @@ export function selectTools( /** * Runs the provided handler with the given client and arguments. */ -export async function executeHandler( - {handler, reqContext, args}: - { - handler: HandlerFunction; - reqContext: McpRequestContext; - args: Record | undefined; - } -): Promise { - return await handler({reqContext, args: args || {}}); +export async function executeHandler({ + handler, + reqContext, + args, +}: { + handler: HandlerFunction; + reqContext: McpRequestContext; + args: Record | undefined; +}): Promise { + return await handler({ reqContext, args: args || {} }); } diff --git a/packages/mcp-server/src/types.ts b/packages/mcp-server/src/types.ts index 52a66b00..2c730de7 100644 --- a/packages/mcp-server/src/types.ts +++ b/packages/mcp-server/src/types.ts @@ -4,41 +4,43 @@ import Writer from 'writer-sdk'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; type TextContentBlock = { - type: "text", - text: string -} + type: 'text'; + text: string; +}; type ImageContentBlock = { - type: "image", - data: string, - mimeType: string -} + type: 'image'; + data: string; + mimeType: string; +}; type AudioContentBlock = { - type: "audio", - data: string, - mimeType: string -} + type: 'audio'; + data: string; + mimeType: string; +}; type ResourceContentBlock = { - type: "resource", - resource: { - uri: string, - mimeType: string, - text: string - } | { - uri: string, - mimeType: string, - blob: string - } -} + type: 'resource'; + resource: + | { + uri: string; + mimeType: string; + text: string; + } + | { + uri: string; + mimeType: string; + blob: string; + }; +}; export type ContentBlock = TextContentBlock | ImageContentBlock | AudioContentBlock | ResourceContentBlock; export type ToolCallResult = { content: ContentBlock[]; isError?: boolean; -} +}; export type McpRequestContext = { client: Writer; @@ -46,7 +48,7 @@ export type McpRequestContext = { upstreamClientEnvs?: Record | undefined; mcpSessionId?: string | undefined; mcpClientInfo?: { name: string; version: string } | undefined; -} +}; export type HandlerFunction = ({ reqContext, @@ -56,9 +58,7 @@ export type HandlerFunction = ({ args: Record | undefined; }) => Promise; -export function asTextContentResult( - result: unknown, -): ToolCallResult { +export function asTextContentResult(result: unknown): ToolCallResult { return { content: [ { @@ -69,24 +69,18 @@ export function asTextContentResult( }; } -export async function asBinaryContentResult( - response: Response, -): Promise { +export async function asBinaryContentResult(response: Response): Promise { const blob = await response.blob(); const mimeType = blob.type; const data = Buffer.from(await blob.arrayBuffer()).toString('base64'); if (mimeType.startsWith('image/')) { return { - content: [ - {type: 'image', mimeType, data} - ] - } + content: [{ type: 'image', mimeType, data }], + }; } else if (mimeType.startsWith('audio/')) { return { - content: [ - {type: 'audio', mimeType, data} - ] - } + content: [{ type: 'audio', mimeType, data }], + }; } else { return { content: [ @@ -104,9 +98,7 @@ export async function asBinaryContentResult( } } -export function asErrorResult( - message: string -): ToolCallResult { +export function asErrorResult(message: string): ToolCallResult { return { content: [ { @@ -128,7 +120,7 @@ export type Metadata = { }; export type McpTool = { - metadata: Metadata, - tool: Tool, - handler: HandlerFunction + metadata: Metadata; + tool: Tool; + handler: HandlerFunction; }; diff --git a/scripts/fast-format b/scripts/fast-format index e1723136..53721ac0 100755 --- a/scripts/fast-format +++ b/scripts/fast-format @@ -31,8 +31,10 @@ if ! [ -z "$ESLINT_FILES" ]; then fi echo "==> Running prettier --write" -PRETTIER_FILES="$(grep '\.\([mc]?tsx?\|[mc]?jsx?\|json\)$' "$FILE_LIST" || true)" +# format things eslint didn't +PRETTIER_FILES="$(grep '\.\(js\|json\)$' "$FILE_LIST" || true)" if ! [ -z "$PRETTIER_FILES" ]; then echo "$PRETTIER_FILES" | xargs ./node_modules/.bin/prettier \ - --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern + --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern \ + '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' fi diff --git a/scripts/format b/scripts/format index b1b2c17a..7a756401 100755 --- a/scripts/format +++ b/scripts/format @@ -8,4 +8,5 @@ echo "==> Running eslint --fix" ./node_modules/.bin/eslint --fix . echo "==> Running prettier --write" -./node_modules/.bin/prettier --write --cache --cache-strategy metadata . +# format things eslint didn't +./node_modules/.bin/prettier --write --cache --cache-strategy metadata . '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' diff --git a/scripts/lint b/scripts/lint index 1f532548..3ffb78a6 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,9 +4,6 @@ set -e cd "$(dirname "$0")/.." -echo "==> Running prettier --check" -./node_modules/.bin/prettier --check . - echo "==> Running eslint" ./node_modules/.bin/eslint . diff --git a/scripts/utils/postprocess-files.cjs b/scripts/utils/postprocess-files.cjs index deae575e..a8cdeb7c 100644 --- a/scripts/utils/postprocess-files.cjs +++ b/scripts/utils/postprocess-files.cjs @@ -23,12 +23,19 @@ async function postprocess() { // strip out lib="dom", types="node", and types="react" references; these // are needed at build time, but would pollute the user's TS environment - const transformed = code.replace( + let transformed = code.replace( /^ *\/\/\/ * ' '.repeat(match.length - 1) + '\n', ); + // TypeScript's declaration emitter collapses /** @ts-ignore */ onto the same + // line as the type declaration, which doesn't work. So we convert to // @ts-ignore + // on its own line to properly suppresses errors. + if (file.endsWith('.d.ts') || file.endsWith('.d.mts') || file.endsWith('.d.cts')) { + transformed = transformed.replace(/\/\*\* @ts-ignore\b[^*]*\*\/ /gm, '// @ts-ignore\n'); + } + if (transformed !== code) { console.error(`wrote ${path.relative(process.cwd(), file)}`); await fs.promises.writeFile(file, transformed, 'utf8'); diff --git a/src/api-promise.ts b/src/api-promise.ts index 4e701286..8c775ee6 100644 --- a/src/api-promise.ts +++ b/src/api-promise.ts @@ -1,2 +1,2 @@ /** @deprecated Import from ./core/api-promise instead */ -export * from "./core/api-promise" \ No newline at end of file +export * from './core/api-promise'; diff --git a/src/client.ts b/src/client.ts index ef491d61..d43b78e2 100644 --- a/src/client.ts +++ b/src/client.ts @@ -15,24 +15,104 @@ import { stringifyQuery } from './internal/utils/query'; import { VERSION } from './version'; import * as Errors from './core/error'; import * as Pagination from './core/pagination'; -import { AbstractPage, type ApplicationJobsOffsetParams, ApplicationJobsOffsetResponse, type CursorPageParams, CursorPageResponse } from './core/pagination'; +import { + AbstractPage, + type ApplicationJobsOffsetParams, + ApplicationJobsOffsetResponse, + type CursorPageParams, + CursorPageResponse, +} from './core/pagination'; import * as Uploads from './core/uploads'; import * as API from './resources/index'; import { APIPromise } from './core/api-promise'; -import { Chat, ChatChatParams, ChatChatParamsNonStreaming, ChatChatParamsStreaming, ChatCompletion, ChatCompletionChoice, ChatCompletionChunk, ChatCompletionMessage, ChatCompletionParams, ChatCompletionUsage } from './resources/chat'; -import { Completion, CompletionChunk, CompletionCreateParams, CompletionCreateParamsNonStreaming, CompletionCreateParamsStreaming, CompletionParams, Completions } from './resources/completions'; -import { File, FileDeleteResponse, FileListParams, FileRetryParams, FileRetryResponse, FileUploadParams, Files, FilesCursorPage } from './resources/files'; -import { Graph, GraphAddFileToGraphParams, GraphCreateParams, GraphCreateResponse, GraphDeleteResponse, GraphListParams, GraphQuestionParams, GraphQuestionParamsNonStreaming, GraphQuestionParamsStreaming, GraphRemoveFileFromGraphParams, GraphRemoveFileFromGraphResponse, GraphUpdateParams, GraphUpdateResponse, Graphs, GraphsCursorPage, Question, QuestionResponseChunk } from './resources/graphs'; +import { + Chat, + ChatChatParams, + ChatChatParamsNonStreaming, + ChatChatParamsStreaming, + ChatCompletion, + ChatCompletionChoice, + ChatCompletionChunk, + ChatCompletionMessage, + ChatCompletionParams, + ChatCompletionUsage, +} from './resources/chat'; +import { + Completion, + CompletionChunk, + CompletionCreateParams, + CompletionCreateParamsNonStreaming, + CompletionCreateParamsStreaming, + CompletionParams, + Completions, +} from './resources/completions'; +import { + File, + FileDeleteResponse, + FileListParams, + FileRetryParams, + FileRetryResponse, + FileUploadParams, + Files, + FilesCursorPage, +} from './resources/files'; +import { + Graph, + GraphAddFileToGraphParams, + GraphCreateParams, + GraphCreateResponse, + GraphDeleteResponse, + GraphListParams, + GraphQuestionParams, + GraphQuestionParamsNonStreaming, + GraphQuestionParamsStreaming, + GraphRemoveFileFromGraphParams, + GraphRemoveFileFromGraphResponse, + GraphUpdateParams, + GraphUpdateResponse, + Graphs, + GraphsCursorPage, + Question, + QuestionResponseChunk, +} from './resources/graphs'; import { ModelListResponse, Models } from './resources/models'; -import { ToolParsePdfParams, ToolParsePdfResponse, ToolWebSearchParams, ToolWebSearchResponse, Tools } from './resources/tools'; -import { Translation, TranslationRequest, TranslationResponse, TranslationTranslateParams } from './resources/translation'; +import { + ToolParsePdfParams, + ToolParsePdfResponse, + ToolWebSearchParams, + ToolWebSearchResponse, + Tools, +} from './resources/tools'; +import { + Translation, + TranslationRequest, + TranslationResponse, + TranslationTranslateParams, +} from './resources/translation'; import { Vision, VisionAnalyzeParams, VisionRequest, VisionResponse } from './resources/vision'; -import { ApplicationGenerateContentChunk, ApplicationGenerateContentParams, ApplicationGenerateContentParamsNonStreaming, ApplicationGenerateContentParamsStreaming, ApplicationGenerateContentResponse, ApplicationListParams, ApplicationListResponse, ApplicationListResponsesCursorPage, ApplicationRetrieveResponse, Applications } from './resources/applications/applications'; +import { + ApplicationGenerateContentChunk, + ApplicationGenerateContentParams, + ApplicationGenerateContentParamsNonStreaming, + ApplicationGenerateContentParamsStreaming, + ApplicationGenerateContentResponse, + ApplicationListParams, + ApplicationListResponse, + ApplicationListResponsesCursorPage, + ApplicationRetrieveResponse, + Applications, +} from './resources/applications/applications'; import { type Fetch } from './internal/builtin-types'; import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers'; import { FinalRequestOptions, RequestOptions } from './internal/request-options'; import { readEnv } from './internal/utils/env'; -import { type LogLevel, type Logger, formatRequestDetails, loggerFor, parseLogLevel } from './internal/utils/log'; +import { + type LogLevel, + type Logger, + formatRequestDetails, + loggerFor, + parseLogLevel, +} from './internal/utils/log'; import { isEmptyObj } from './internal/utils/values'; export interface ClientOptions { @@ -111,7 +191,7 @@ export interface ClientOptions { } /** - * API Client for interfacing with the Writer API. + * API Client for interfacing with the Writer API. */ export class Writer { apiKey: string; @@ -147,7 +227,7 @@ export class Writer { }: ClientOptions = {}) { if (apiKey === undefined) { throw new Errors.WriterError( - 'The WRITER_API_KEY environment variable is missing or empty; either provide it, or instantiate the Writer client with an apiKey option, like new Writer({ apiKey: \'My API Key\' }).' + "The WRITER_API_KEY environment variable is missing or empty; either provide it, or instantiate the Writer client with an apiKey option, like new Writer({ apiKey: 'My API Key' }).", ); } @@ -163,7 +243,10 @@ export class Writer { const defaultLogLevel = 'warn'; // Set default logLevel early so that we can log a warning in parseLogLevel. this.logLevel = defaultLogLevel; - this.logLevel = parseLogLevel(options.logLevel, 'ClientOptions.logLevel', this) ?? parseLogLevel(readEnv('WRITER_LOG'), 'process.env[\'WRITER_LOG\']', this) ?? defaultLogLevel; + this.logLevel = + parseLogLevel(options.logLevel, 'ClientOptions.logLevel', this) ?? + parseLogLevel(readEnv('WRITER_LOG'), "process.env['WRITER_LOG']", this) ?? + defaultLogLevel; this.fetchOptions = options.fetchOptions; this.maxRetries = options.maxRetries ?? 7; this.fetch = options.fetch ?? Shims.getDefaultFetch(); @@ -188,7 +271,7 @@ export class Writer { fetch: this.fetch, fetchOptions: this.fetchOptions, apiKey: this.apiKey, - ...options + ...options, }); return client; } @@ -201,7 +284,7 @@ export class Writer { } protected defaultQuery(): Record | undefined { - return this._options.defaultQuery + return this._options.defaultQuery; } protected validateHeaders({ values, nulls }: NullableHeaders) { @@ -236,7 +319,11 @@ export class Writer { return Errors.APIError.generate(status, error, message, headers); } - buildURL(path: string, query: Record | null | undefined, defaultBaseURL?: string | undefined): string { + buildURL( + path: string, + query: Record | null | undefined, + defaultBaseURL?: string | undefined, + ): string { const baseURL = (!this.#baseURLOverridden() && defaultBaseURL) || this.baseURL; const url = isAbsoluteURL(path) ? @@ -324,7 +411,9 @@ export class Writer { await this.prepareOptions(options); - const { req, url, timeout } = await this.buildRequest(options, { retryCount: maxRetries - retriesRemaining }); + const { req, url, timeout } = await this.buildRequest(options, { + retryCount: maxRetries - retriesRemaining, + }); await this.prepareRequest(req, { url, options }); @@ -333,7 +422,16 @@ export class Writer { const retryLogStr = retryOfRequestLogID === undefined ? '' : `, retryOf: ${retryOfRequestLogID}`; const startTime = Date.now(); - loggerFor(this).debug(`[${requestLogID}] sending request`, formatRequestDetails({ retryOfRequestLogID, method: options.method, url, options, headers: req.headers })); + loggerFor(this).debug( + `[${requestLogID}] sending request`, + formatRequestDetails({ + retryOfRequestLogID, + method: options.method, + url, + options, + headers: req.headers, + }), + ); if (options.signal?.aborted) { throw new Errors.APIUserAbortError(); @@ -352,21 +450,45 @@ export class Writer { // deno throws "TypeError: error sending request for url (https://example/): client error (Connect): tcp connect error: Operation timed out (os error 60): Operation timed out (os error 60)" // undici throws "TypeError: fetch failed" with cause "ConnectTimeoutError: Connect Timeout Error (attempted address: example:443, timeout: 1ms)" // others do not provide enough information to distinguish timeouts from other connection errors - const isTimeout = isAbortError(response) || /timed? ?out/i.test(String(response) + ('cause' in response ? String(response.cause) : '')) + const isTimeout = + isAbortError(response) || + /timed? ?out/i.test(String(response) + ('cause' in response ? String(response.cause) : '')); if (retriesRemaining) { - loggerFor(this).info(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - ${retryMessage}`) - loggerFor(this).debug(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (${retryMessage})`, formatRequestDetails({ retryOfRequestLogID, url, durationMs: headersTime - startTime, message: response.message })); + loggerFor(this).info( + `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - ${retryMessage}`, + ); + loggerFor(this).debug( + `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (${retryMessage})`, + formatRequestDetails({ + retryOfRequestLogID, + url, + durationMs: headersTime - startTime, + message: response.message, + }), + ); return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID); } - loggerFor(this).info(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - error; no more retries left`) - loggerFor(this).debug(`[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (error; no more retries left)`, formatRequestDetails({ retryOfRequestLogID, url, durationMs: headersTime - startTime, message: response.message })); + loggerFor(this).info( + `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - error; no more retries left`, + ); + loggerFor(this).debug( + `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (error; no more retries left)`, + formatRequestDetails({ + retryOfRequestLogID, + url, + durationMs: headersTime - startTime, + message: response.message, + }), + ); if (isTimeout) { throw new Errors.APIConnectionTimeoutError(); } throw new Errors.APIConnectionError({ cause: response }); } - const responseInfo = `[${requestLogID}${retryLogStr}] ${req.method} ${url} ${response.ok ? 'succeeded' : 'failed'} with status ${response.status} in ${headersTime - startTime}ms`; + const responseInfo = `[${requestLogID}${retryLogStr}] ${req.method} ${url} ${ + response.ok ? 'succeeded' : 'failed' + } with status ${response.status} in ${headersTime - startTime}ms`; if (!response.ok) { const shouldRetry = await this.shouldRetry(response); @@ -375,27 +497,60 @@ export class Writer { // We don't need the body of this response. await Shims.CancelReadableStream(response.body); - loggerFor(this).info(`${responseInfo} - ${retryMessage}`) - loggerFor(this).debug(`[${requestLogID}] response error (${retryMessage})`, formatRequestDetails({ retryOfRequestLogID, url: response.url, status: response.status, headers: response.headers, durationMs: headersTime - startTime })); - return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID, response.headers); + loggerFor(this).info(`${responseInfo} - ${retryMessage}`); + loggerFor(this).debug( + `[${requestLogID}] response error (${retryMessage})`, + formatRequestDetails({ + retryOfRequestLogID, + url: response.url, + status: response.status, + headers: response.headers, + durationMs: headersTime - startTime, + }), + ); + return this.retryRequest( + options, + retriesRemaining, + retryOfRequestLogID ?? requestLogID, + response.headers, + ); } const retryMessage = shouldRetry ? `error; no more retries left` : `error; not retryable`; - loggerFor(this).info(`${responseInfo} - ${retryMessage}`) + loggerFor(this).info(`${responseInfo} - ${retryMessage}`); const errText = await response.text().catch((err: any) => castToError(err).message); const errJSON = safeJSON(errText) as any; const errMessage = errJSON ? undefined : errText; - loggerFor(this).debug(`[${requestLogID}] response error (${retryMessage})`, formatRequestDetails({ retryOfRequestLogID, url: response.url, status: response.status, headers: response.headers, message: errMessage, durationMs: Date.now() - startTime })); + loggerFor(this).debug( + `[${requestLogID}] response error (${retryMessage})`, + formatRequestDetails({ + retryOfRequestLogID, + url: response.url, + status: response.status, + headers: response.headers, + message: errMessage, + durationMs: Date.now() - startTime, + }), + ); const err = this.makeStatusError(response.status, errJSON, errMessage, response.headers); throw err; } - loggerFor(this).info(responseInfo) - loggerFor(this).debug(`[${requestLogID}] response start`, formatRequestDetails({ retryOfRequestLogID, url: response.url, status: response.status, headers: response.headers, durationMs: headersTime - startTime })); + loggerFor(this).info(responseInfo); + loggerFor(this).debug( + `[${requestLogID}] response start`, + formatRequestDetails({ + retryOfRequestLogID, + url: response.url, + status: response.status, + headers: response.headers, + durationMs: headersTime - startTime, + }), + ); return { response, options, controller, requestLogID, retryOfRequestLogID, startTime }; } @@ -413,7 +568,10 @@ export class Writer { ); } - requestAPIList = Pagination.AbstractPage>( + requestAPIList< + Item = unknown, + PageClass extends Pagination.AbstractPage = Pagination.AbstractPage, + >( Page: new (...args: ConstructorParameters) => PageClass, options: PromiseOrValue, ): Pagination.PagePromise { @@ -433,7 +591,9 @@ export class Writer { const timeout = setTimeout(abort, ms); - const isReadableBody = ((globalThis as any).ReadableStream && options.body instanceof (globalThis as any).ReadableStream) || (typeof options.body === "object" && options.body !== null && Symbol.asyncIterator in options.body); + const isReadableBody = + ((globalThis as any).ReadableStream && options.body instanceof (globalThis as any).ReadableStream) || + (typeof options.body === 'object' && options.body !== null && Symbol.asyncIterator in options.body); const fetchOptions: RequestInit = { signal: controller.signal as any, @@ -448,7 +608,6 @@ export class Writer { } try { - // use undefined this binding; fetch errors if bound to something else in browser/cloudflare return await this.fetch.call(undefined, url, fetchOptions); } finally { @@ -549,11 +708,12 @@ export class Writer { const req: FinalizedRequestInit = { method, headers: reqHeaders, - ...(options.signal && { signal: options.signal}), - ...((globalThis as any).ReadableStream && body instanceof (globalThis as any).ReadableStream && { duplex: "half" }), + ...(options.signal && { signal: options.signal }), + ...((globalThis as any).ReadableStream && + body instanceof (globalThis as any).ReadableStream && { duplex: 'half' }), ...(body && { body }), - ...(this.fetchOptions as any ?? {}), - ...(options.fetchOptions as any ?? {}), + ...((this.fetchOptions as any) ?? {}), + ...((options.fetchOptions as any) ?? {}), }; return { req, url, timeout: options.timeout }; @@ -578,15 +738,17 @@ export class Writer { const headers = buildHeaders([ idempotencyHeaders, - {Accept: 'application/json', - 'User-Agent': this.getUserAgent(), - 'X-Stainless-Retry-Count': String(retryCount), - ...(options.timeout ? { 'X-Stainless-Timeout': String(Math.trunc(options.timeout / 1000)) } : {}), - ...getPlatformHeaders()}, + { + Accept: 'application/json', + 'User-Agent': this.getUserAgent(), + 'X-Stainless-Retry-Count': String(retryCount), + ...(options.timeout ? { 'X-Stainless-Timeout': String(Math.trunc(options.timeout / 1000)) } : {}), + ...getPlatformHeaders(), + }, await this.authHeaders(options), this._options.defaultHeaders, bodyHeaders, - options.headers + options.headers, ]); this.validateHeaders(headers); @@ -613,11 +775,9 @@ export class Writer { ArrayBuffer.isView(body) || body instanceof ArrayBuffer || body instanceof DataView || - ( - typeof body === 'string' && + (typeof body === 'string' && // Preserve legacy string encoding behavior for now - headers.values.has('content-type') - ) || + headers.values.has('content-type')) || // `Blob` is superset of `File` ((globalThis as any).Blob && body instanceof (globalThis as any).Blob) || // `FormData` -> `multipart/form-data` @@ -648,7 +808,7 @@ export class Writer { } static Writer = this; - static DEFAULT_TIMEOUT = 180000 // 3 minutes + static DEFAULT_TIMEOUT = 180000; // 3 minutes static WriterError = Errors.WriterError; static APIError = Errors.APIError; @@ -688,125 +848,119 @@ Writer.Translation = Translation; Writer.Vision = Vision; export declare namespace Writer { - export type RequestOptions = Opts.RequestOptions; - - export import CursorPage = Pagination.CursorPage; -export { - type CursorPageParams as CursorPageParams, - type CursorPageResponse as CursorPageResponse -}; - -export import ApplicationJobsOffset = Pagination.ApplicationJobsOffset; -export { - type ApplicationJobsOffsetParams as ApplicationJobsOffsetParams, - type ApplicationJobsOffsetResponse as ApplicationJobsOffsetResponse -}; - -export { - Applications as Applications, - type ApplicationGenerateContentChunk as ApplicationGenerateContentChunk, - type ApplicationGenerateContentResponse as ApplicationGenerateContentResponse, - type ApplicationRetrieveResponse as ApplicationRetrieveResponse, - type ApplicationListResponse as ApplicationListResponse, - type ApplicationListResponsesCursorPage as ApplicationListResponsesCursorPage, - type ApplicationListParams as ApplicationListParams, - type ApplicationGenerateContentParams as ApplicationGenerateContentParams, - type ApplicationGenerateContentParamsNonStreaming as ApplicationGenerateContentParamsNonStreaming, - type ApplicationGenerateContentParamsStreaming as ApplicationGenerateContentParamsStreaming -}; - -export { - Chat as Chat, - type ChatCompletion as ChatCompletion, - type ChatCompletionChoice as ChatCompletionChoice, - type ChatCompletionChunk as ChatCompletionChunk, - type ChatCompletionMessage as ChatCompletionMessage, - type ChatCompletionParams as ChatCompletionParams, - type ChatCompletionUsage as ChatCompletionUsage, - type ChatChatParams as ChatChatParams, - type ChatChatParamsNonStreaming as ChatChatParamsNonStreaming, - type ChatChatParamsStreaming as ChatChatParamsStreaming -}; - -export { - Completions as Completions, - type Completion as Completion, - type CompletionChunk as CompletionChunk, - type CompletionParams as CompletionParams, - type CompletionCreateParams as CompletionCreateParams, - type CompletionCreateParamsNonStreaming as CompletionCreateParamsNonStreaming, - type CompletionCreateParamsStreaming as CompletionCreateParamsStreaming -}; - -export { - Models as Models, - type ModelListResponse as ModelListResponse -}; - -export { - Graphs as Graphs, - type Graph as Graph, - type Question as Question, - type QuestionResponseChunk as QuestionResponseChunk, - type GraphCreateResponse as GraphCreateResponse, - type GraphUpdateResponse as GraphUpdateResponse, - type GraphDeleteResponse as GraphDeleteResponse, - type GraphRemoveFileFromGraphResponse as GraphRemoveFileFromGraphResponse, - type GraphsCursorPage as GraphsCursorPage, - type GraphCreateParams as GraphCreateParams, - type GraphUpdateParams as GraphUpdateParams, - type GraphListParams as GraphListParams, - type GraphAddFileToGraphParams as GraphAddFileToGraphParams, - type GraphQuestionParams as GraphQuestionParams, - type GraphQuestionParamsNonStreaming as GraphQuestionParamsNonStreaming, - type GraphQuestionParamsStreaming as GraphQuestionParamsStreaming, - type GraphRemoveFileFromGraphParams as GraphRemoveFileFromGraphParams -}; - -export { - Files as Files, - type File as File, - type FileDeleteResponse as FileDeleteResponse, - type FileRetryResponse as FileRetryResponse, - type FilesCursorPage as FilesCursorPage, - type FileListParams as FileListParams, - type FileRetryParams as FileRetryParams, - type FileUploadParams as FileUploadParams -}; - -export { - Tools as Tools, - type ToolParsePdfResponse as ToolParsePdfResponse, - type ToolWebSearchResponse as ToolWebSearchResponse, - type ToolParsePdfParams as ToolParsePdfParams, - type ToolWebSearchParams as ToolWebSearchParams -}; - -export { - Translation as Translation, - type TranslationRequest as TranslationRequest, - type TranslationResponse as TranslationResponse, - type TranslationTranslateParams as TranslationTranslateParams -}; - -export { - Vision as Vision, - type VisionRequest as VisionRequest, - type VisionResponse as VisionResponse, - type VisionAnalyzeParams as VisionAnalyzeParams -}; - -export type ErrorMessage = API.ErrorMessage; -export type ErrorObject = API.ErrorObject; -export type FunctionDefinition = API.FunctionDefinition; -export type FunctionParams = API.FunctionParams; -export type GraphData = API.GraphData; -export type Logprobs = API.Logprobs; -export type LogprobsToken = API.LogprobsToken; -export type Source = API.Source; -export type ToolCall = API.ToolCall; -export type ToolCallStreaming = API.ToolCallStreaming; -export type ToolChoiceJsonObject = API.ToolChoiceJsonObject; -export type ToolChoiceString = API.ToolChoiceString; -export type ToolParam = API.ToolParam; - } + export type RequestOptions = Opts.RequestOptions; + + export import CursorPage = Pagination.CursorPage; + export { type CursorPageParams as CursorPageParams, type CursorPageResponse as CursorPageResponse }; + + export import ApplicationJobsOffset = Pagination.ApplicationJobsOffset; + export { + type ApplicationJobsOffsetParams as ApplicationJobsOffsetParams, + type ApplicationJobsOffsetResponse as ApplicationJobsOffsetResponse, + }; + + export { + Applications as Applications, + type ApplicationGenerateContentChunk as ApplicationGenerateContentChunk, + type ApplicationGenerateContentResponse as ApplicationGenerateContentResponse, + type ApplicationRetrieveResponse as ApplicationRetrieveResponse, + type ApplicationListResponse as ApplicationListResponse, + type ApplicationListResponsesCursorPage as ApplicationListResponsesCursorPage, + type ApplicationListParams as ApplicationListParams, + type ApplicationGenerateContentParams as ApplicationGenerateContentParams, + type ApplicationGenerateContentParamsNonStreaming as ApplicationGenerateContentParamsNonStreaming, + type ApplicationGenerateContentParamsStreaming as ApplicationGenerateContentParamsStreaming, + }; + + export { + Chat as Chat, + type ChatCompletion as ChatCompletion, + type ChatCompletionChoice as ChatCompletionChoice, + type ChatCompletionChunk as ChatCompletionChunk, + type ChatCompletionMessage as ChatCompletionMessage, + type ChatCompletionParams as ChatCompletionParams, + type ChatCompletionUsage as ChatCompletionUsage, + type ChatChatParams as ChatChatParams, + type ChatChatParamsNonStreaming as ChatChatParamsNonStreaming, + type ChatChatParamsStreaming as ChatChatParamsStreaming, + }; + + export { + Completions as Completions, + type Completion as Completion, + type CompletionChunk as CompletionChunk, + type CompletionParams as CompletionParams, + type CompletionCreateParams as CompletionCreateParams, + type CompletionCreateParamsNonStreaming as CompletionCreateParamsNonStreaming, + type CompletionCreateParamsStreaming as CompletionCreateParamsStreaming, + }; + + export { Models as Models, type ModelListResponse as ModelListResponse }; + + export { + Graphs as Graphs, + type Graph as Graph, + type Question as Question, + type QuestionResponseChunk as QuestionResponseChunk, + type GraphCreateResponse as GraphCreateResponse, + type GraphUpdateResponse as GraphUpdateResponse, + type GraphDeleteResponse as GraphDeleteResponse, + type GraphRemoveFileFromGraphResponse as GraphRemoveFileFromGraphResponse, + type GraphsCursorPage as GraphsCursorPage, + type GraphCreateParams as GraphCreateParams, + type GraphUpdateParams as GraphUpdateParams, + type GraphListParams as GraphListParams, + type GraphAddFileToGraphParams as GraphAddFileToGraphParams, + type GraphQuestionParams as GraphQuestionParams, + type GraphQuestionParamsNonStreaming as GraphQuestionParamsNonStreaming, + type GraphQuestionParamsStreaming as GraphQuestionParamsStreaming, + type GraphRemoveFileFromGraphParams as GraphRemoveFileFromGraphParams, + }; + + export { + Files as Files, + type File as File, + type FileDeleteResponse as FileDeleteResponse, + type FileRetryResponse as FileRetryResponse, + type FilesCursorPage as FilesCursorPage, + type FileListParams as FileListParams, + type FileRetryParams as FileRetryParams, + type FileUploadParams as FileUploadParams, + }; + + export { + Tools as Tools, + type ToolParsePdfResponse as ToolParsePdfResponse, + type ToolWebSearchResponse as ToolWebSearchResponse, + type ToolParsePdfParams as ToolParsePdfParams, + type ToolWebSearchParams as ToolWebSearchParams, + }; + + export { + Translation as Translation, + type TranslationRequest as TranslationRequest, + type TranslationResponse as TranslationResponse, + type TranslationTranslateParams as TranslationTranslateParams, + }; + + export { + Vision as Vision, + type VisionRequest as VisionRequest, + type VisionResponse as VisionResponse, + type VisionAnalyzeParams as VisionAnalyzeParams, + }; + + export type ErrorMessage = API.ErrorMessage; + export type ErrorObject = API.ErrorObject; + export type FunctionDefinition = API.FunctionDefinition; + export type FunctionParams = API.FunctionParams; + export type GraphData = API.GraphData; + export type Logprobs = API.Logprobs; + export type LogprobsToken = API.LogprobsToken; + export type Source = API.Source; + export type ToolCall = API.ToolCall; + export type ToolCallStreaming = API.ToolCallStreaming; + export type ToolChoiceJsonObject = API.ToolChoiceJsonObject; + export type ToolChoiceString = API.ToolChoiceString; + export type ToolParam = API.ToolParam; +} diff --git a/src/core/api-promise.ts b/src/core/api-promise.ts index 5cfa992c..1552d0f2 100644 --- a/src/core/api-promise.ts +++ b/src/core/api-promise.ts @@ -16,7 +16,10 @@ export class APIPromise extends Promise { constructor( client: Writer, private responsePromise: Promise, - private parseResponse: (client: Writer, props: APIResponseProps) => PromiseOrValue = defaultParseResponse, + private parseResponse: ( + client: Writer, + props: APIResponseProps, + ) => PromiseOrValue = defaultParseResponse, ) { super((resolve) => { // this is maybe a bit weird but this has to be a no-op to not implicitly @@ -28,7 +31,9 @@ export class APIPromise extends Promise { } _thenUnwrap(transform: (data: T, props: APIResponseProps) => U): APIPromise { - return new APIPromise(this.#client, this.responsePromise, async (client, props) => transform(await this.parseResponse(client, props), props)); + return new APIPromise(this.#client, this.responsePromise, async (client, props) => + transform(await this.parseResponse(client, props), props), + ); } /** diff --git a/src/core/error.ts b/src/core/error.ts index 41996f70..ddd70d3e 100644 --- a/src/core/error.ts +++ b/src/core/error.ts @@ -2,10 +2,13 @@ import { castToError } from '../internal/errors'; -export class WriterError extends Error { -} +export class WriterError extends Error {} -export class APIError extends WriterError { +export class APIError< + TStatus extends number | undefined = number | undefined, + THeaders extends Headers | undefined = Headers | undefined, + TError extends Object | undefined = Object | undefined, +> extends WriterError { /** HTTP status for the response that caused the error */ readonly status: TStatus; /** HTTP headers for the response that caused the error */ @@ -13,9 +16,6 @@ export class APIError { -} +export class BadRequestError extends APIError<400, Headers> {} -export class AuthenticationError extends APIError<401, Headers> { -} +export class AuthenticationError extends APIError<401, Headers> {} -export class PermissionDeniedError extends APIError<403, Headers> { -} +export class PermissionDeniedError extends APIError<403, Headers> {} -export class NotFoundError extends APIError<404, Headers> { -} +export class NotFoundError extends APIError<404, Headers> {} -export class ConflictError extends APIError<409, Headers> { -} +export class ConflictError extends APIError<409, Headers> {} -export class UnprocessableEntityError extends APIError<422, Headers> { -} +export class UnprocessableEntityError extends APIError<422, Headers> {} -export class RateLimitError extends APIError<429, Headers> { -} +export class RateLimitError extends APIError<429, Headers> {} -export class InternalServerError extends APIError { -} +export class InternalServerError extends APIError {} export class LengthFinishReasonError extends WriterError { constructor() { diff --git a/src/core/pagination.ts b/src/core/pagination.ts index 266b2c18..383535e1 100644 --- a/src/core/pagination.ts +++ b/src/core/pagination.ts @@ -87,7 +87,8 @@ export class PagePromise< super( client, request, - async (client, props) => new Page(client, props.response, await defaultParseResponse(client, props), props.options) + async (client, props) => + new Page(client, props.response, await defaultParseResponse(client, props), props.options), ); } @@ -126,12 +127,20 @@ export interface CursorPageParams { before?: string; } -export class CursorPage extends AbstractPage implements CursorPageResponse { +export class CursorPage + extends AbstractPage + implements CursorPageResponse +{ data: Array; has_more: boolean; - constructor(client: Writer, response: Response, body: CursorPageResponse, options: FinalRequestOptions) { + constructor( + client: Writer, + response: Response, + body: CursorPageResponse, + options: FinalRequestOptions, + ) { super(client, response, body, options); this.data = body.data || []; @@ -165,7 +174,7 @@ export class CursorPage extends AbstractPage }; } - const id = data[0]?.id + const id = data[0]?.id; if (!id) { return null; } @@ -208,14 +217,22 @@ export interface ApplicationJobsOffsetParams { limit?: number; } -export class ApplicationJobsOffset extends AbstractPage implements ApplicationJobsOffsetResponse { +export class ApplicationJobsOffset + extends AbstractPage + implements ApplicationJobsOffsetResponse +{ result: Array; totalCount: number; pagination: ApplicationJobsOffsetResponse.Pagination; - constructor(client: Writer, response: Response, body: ApplicationJobsOffsetResponse, options: FinalRequestOptions) { + constructor( + client: Writer, + response: Response, + body: ApplicationJobsOffsetResponse, + options: FinalRequestOptions, + ) { super(client, response, body, options); this.result = body.result || []; @@ -239,14 +256,14 @@ export class ApplicationJobsOffset extends AbstractPage implements A if (currentCount < totalCount) { return { - ...this.options, - query: { - ...maybeObj(this.options.query), - offset: currentCount, - }, - }; + ...this.options, + query: { + ...maybeObj(this.options.query), + offset: currentCount, + }, + }; } - return null + return null; } } diff --git a/src/core/streaming.ts b/src/core/streaming.ts index 5bdc2abf..82383c28 100644 --- a/src/core/streaming.ts +++ b/src/core/streaming.ts @@ -9,7 +9,7 @@ import { encodeUTF8 } from '../internal/utils/bytes'; import { loggerFor } from '../internal/utils/log'; import type { Writer } from '../client'; -import { APIError } from './error';; +import { APIError } from './error'; type Bytes = string | ArrayBuffer | Uint8Array | null | undefined; @@ -32,29 +32,29 @@ export class Stream implements AsyncIterable { this.#client = client; } - static fromSSEResponse(response: Response, -controller: AbortController, -client?: Writer,): Stream { + static fromSSEResponse( + response: Response, + controller: AbortController, + client?: Writer, + ): Stream { let consumed = false; const logger = client ? loggerFor(client) : console; async function* iterator(): AsyncIterator { if (consumed) { - throw new WriterError( - 'Cannot iterate over a consumed stream, use `.tee()` to split the stream.', - ); + throw new WriterError('Cannot iterate over a consumed stream, use `.tee()` to split the stream.'); } consumed = true; let done = false; try { for await (const sse of _iterSSEMessages(response, controller)) { if (done) continue; - + if (sse.data.startsWith('[DONE]')) { done = true; continue; } - + if (sse.event === null) { try { yield JSON.parse(sse.data) as Item; @@ -64,10 +64,10 @@ client?: Writer,): Stream { throw e; } } - + if (sse.event === 'error') { throw new APIError(undefined, safeJSON(sse.data) ?? sse.data, undefined, response.headers); - }; + } } done = true; } catch (e) { @@ -111,9 +111,7 @@ client?: Writer,): Stream { async function* iterator(): AsyncIterator { if (consumed) { - throw new WriterError( - 'Cannot iterate over a consumed stream, use `.tee()` to split the stream.', - ); + throw new WriterError('Cannot iterate over a consumed stream, use `.tee()` to split the stream.'); } consumed = true; let done = false; diff --git a/src/error.ts b/src/error.ts index d0832d34..fc55f46c 100644 --- a/src/error.ts +++ b/src/error.ts @@ -1,2 +1,2 @@ /** @deprecated Import from ./core/error instead */ -export * from "./core/error" \ No newline at end of file +export * from './core/error'; diff --git a/src/index.ts b/src/index.ts index def542ca..188418c8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,4 +6,18 @@ export { type Uploadable, toFile } from './core/uploads'; export { APIPromise } from './core/api-promise'; export { Writer, type ClientOptions } from './client'; export { PagePromise } from './core/pagination'; -export { WriterError, APIError, APIConnectionError, APIConnectionTimeoutError, APIUserAbortError, NotFoundError, ConflictError, RateLimitError, BadRequestError, AuthenticationError, InternalServerError, PermissionDeniedError, UnprocessableEntityError } from './core/error'; +export { + WriterError, + APIError, + APIConnectionError, + APIConnectionTimeoutError, + APIUserAbortError, + NotFoundError, + ConflictError, + RateLimitError, + BadRequestError, + AuthenticationError, + InternalServerError, + PermissionDeniedError, + UnprocessableEntityError, +} from './core/error'; diff --git a/src/internal/builtin-types.ts b/src/internal/builtin-types.ts index 6059d5db..c23d3bde 100644 --- a/src/internal/builtin-types.ts +++ b/src/internal/builtin-types.ts @@ -1,23 +1,20 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -export type Fetch = ( - input: string | URL | Request, - init?: RequestInit, -) => Promise +export type Fetch = (input: string | URL | Request, init?: RequestInit) => Promise; /** * An alias to the builtin `RequestInit` type so we can * easily alias it in import statements if there are name clashes. - * - * https://developer.mozilla.org/docs/Web/API/RequestInit + * + * https://developer.mozilla.org/docs/Web/API/RequestInit */ type _RequestInit = RequestInit; /** * An alias to the builtin `Response` type so we can * easily alias it in import statements if there are name clashes. - * - * https://developer.mozilla.org/docs/Web/API/Response + * + * https://developer.mozilla.org/docs/Web/API/Response */ type _Response = Response; @@ -54,7 +51,15 @@ type _Array = Array; */ type _Record = Record; -export type { _Array as Array, _BodyInit as BodyInit, _HeadersInit as HeadersInit, _Record as Record, _RequestInfo as RequestInfo, _RequestInit as RequestInit, _Response as Response }; +export type { + _Array as Array, + _BodyInit as BodyInit, + _HeadersInit as HeadersInit, + _Record as Record, + _RequestInfo as RequestInfo, + _RequestInit as RequestInit, + _Response as Response, +}; /** * A copy of the builtin `EndingType` type as it isn't fully supported in certain diff --git a/src/internal/detect-platform.ts b/src/internal/detect-platform.ts index 394ede88..e82d95c9 100644 --- a/src/internal/detect-platform.ts +++ b/src/internal/detect-platform.ts @@ -25,7 +25,11 @@ function getDetectedPlatform(): DetectedPlatform { if (typeof EdgeRuntime !== 'undefined') { return 'edge'; } - if (Object.prototype.toString.call(typeof (globalThis as any).process !== 'undefined' ? (globalThis as any).process : 0) === '[object process]') { + if ( + Object.prototype.toString.call( + typeof (globalThis as any).process !== 'undefined' ? (globalThis as any).process : 0, + ) === '[object process]' + ) { return 'node'; } return 'unknown'; diff --git a/src/internal/errors.ts b/src/internal/errors.ts index c14a742b..82c7b14d 100644 --- a/src/internal/errors.ts +++ b/src/internal/errors.ts @@ -2,12 +2,12 @@ export function isAbortError(err: unknown) { return ( - typeof err === 'object' && err !== null && ( - // Spec-compliant fetch implementations - ('name' in err && (err as any).name === 'AbortError') || + typeof err === 'object' && + err !== null && + // Spec-compliant fetch implementations + (('name' in err && (err as any).name === 'AbortError') || // Expo fetch - ('message' in err && String((err as any).message).includes('FetchRequestCanceledException')) - ) + ('message' in err && String((err as any).message).includes('FetchRequestCanceledException'))) ); } @@ -24,10 +24,10 @@ export const castToError = (err: any): Error => { if (err.name) error.name = err.name; return error; } - } catch { } + } catch {} try { return new Error(JSON.stringify(err)); - } catch { } + } catch {} } return new Error(err); }; diff --git a/src/internal/headers.ts b/src/internal/headers.ts index fa2ea2b9..c724a9d2 100644 --- a/src/internal/headers.ts +++ b/src/internal/headers.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { isReadonlyArray } from "./utils/values"; +import { isReadonlyArray } from './utils/values'; type HeaderValue = string | undefined | null; export type HeadersLike = @@ -51,7 +51,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator(client: Writer, props: APIResponse const text = await response.text(); return text as unknown as T; })(); - loggerFor(client).debug(`[${requestLogID}] response parsed`, formatRequestDetails({ retryOfRequestLogID, url: response.url, status: response.status, body, durationMs: Date.now() - startTime })); + loggerFor(client).debug( + `[${requestLogID}] response parsed`, + formatRequestDetails({ + retryOfRequestLogID, + url: response.url, + status: response.status, + body, + durationMs: Date.now() - startTime, + }), + ); return body; } diff --git a/src/internal/request-options.ts b/src/internal/request-options.ts index 4dbdbd18..493c1ce3 100644 --- a/src/internal/request-options.ts +++ b/src/internal/request-options.ts @@ -77,14 +77,11 @@ export type RequestOptions = { defaultBaseURL?: string | undefined; __binaryResponse?: boolean | undefined; - __streamClass?: typeof Stream + __streamClass?: typeof Stream; }; export type EncodedContent = { bodyHeaders: HeadersLike; body: BodyInit }; -export type RequestEncoder = (request: { - headers: NullableHeaders; - body: unknown; -}) => EncodedContent; +export type RequestEncoder = (request: { headers: NullableHeaders; body: unknown }) => EncodedContent; export const FallbackEncoder: RequestEncoder = ({ headers, body }) => { return { diff --git a/src/internal/shim-types.ts b/src/internal/shim-types.ts index accbf576..8ddf7b0a 100644 --- a/src/internal/shim-types.ts +++ b/src/internal/shim-types.ts @@ -19,8 +19,8 @@ type _ConditionalNodeReadableStream = typeof globalThis extends { ReadableStream: any } ? never : _NodeReadableStream; type _ReadableStream = NeverToAny< - ([0] extends [1 & _DOMReadableStream] ? never : _DOMReadableStream) | - ([0] extends [1 & _ConditionalNodeReadableStream] ? never : _ConditionalNodeReadableStream) + | ([0] extends [1 & _DOMReadableStream] ? never : _DOMReadableStream) + | ([0] extends [1 & _ConditionalNodeReadableStream] ? never : _ConditionalNodeReadableStream) >; export type { _ReadableStream as ReadableStream }; diff --git a/src/internal/shims.ts b/src/internal/shims.ts index dfcfbbf0..da6f0097 100644 --- a/src/internal/shims.ts +++ b/src/internal/shims.ts @@ -27,7 +27,9 @@ export function makeReadableStream(...args: ReadableStreamArgs): ReadableStream if (typeof ReadableStream === 'undefined') { // Note: All of the platforms / runtimes we officially support already define // `ReadableStream` as a global, so this should only ever be hit on unsupported runtimes. - throw new Error('`ReadableStream` is not defined as a global; You will need to polyfill it, `globalThis.ReadableStream = ReadableStream`'); + throw new Error( + '`ReadableStream` is not defined as a global; You will need to polyfill it, `globalThis.ReadableStream = ReadableStream`', + ); } return new ReadableStream(...args); diff --git a/src/internal/to-file.ts b/src/internal/to-file.ts index c72a2b41..30eada32 100644 --- a/src/internal/to-file.ts +++ b/src/internal/to-file.ts @@ -1,4 +1,4 @@ -import { BlobPart, getName, makeFile, isAsyncIterable } from "./uploads"; +import { BlobPart, getName, makeFile, isAsyncIterable } from './uploads'; import type { FilePropertyBag } from './builtin-types'; import { checkFileSupport } from './uploads'; @@ -65,8 +65,11 @@ const isResponseLike = (value: any): value is ResponseLike => typeof value.url === 'string' && typeof value.blob === 'function'; -export type ToFileInput = FileLike | ResponseLike | Exclude | AsyncIterable; - +export type ToFileInput = + | FileLike + | ResponseLike + | Exclude + | AsyncIterable; /** * Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats @@ -116,9 +119,7 @@ export async function toFile( return makeFile(parts, name, options); } -async function getBytes( - value: BlobLikePart | AsyncIterable, -): Promise> { +async function getBytes(value: BlobLikePart | AsyncIterable): Promise> { let parts: Array = []; if ( typeof value === 'string' || @@ -151,4 +152,3 @@ function propsForError(value: unknown): string { const props = Object.getOwnPropertyNames(value); return `; props: [${props.map((p) => `"${p}"`).join(', ')}]`; } - diff --git a/src/internal/types.ts b/src/internal/types.ts index c45fee32..b668dfc0 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -7,34 +7,40 @@ export type KeysEnum = { [P in keyof Required]: true }; export type FinalizedRequestInit = RequestInit & { headers: Headers }; -type NotAny = [0] extends [(1 & T)] ? never : T; +type NotAny = [0] extends [1 & T] ? never : T; /** * Some environments overload the global fetch function, and Parameters only gets the last signature. */ -type OverloadedParameters = T extends { - (...args: infer A): unknown; - (...args: infer B): unknown; - (...args: infer C): unknown; - (...args: infer D): unknown; -} - ? A | B | C | D - : T extends { +type OverloadedParameters = + T extends ( + { (...args: infer A): unknown; (...args: infer B): unknown; (...args: infer C): unknown; + (...args: infer D): unknown; } - ? A | B | C - : T extends { + ) ? + A | B | C | D + : T extends ( + { + (...args: infer A): unknown; + (...args: infer B): unknown; + (...args: infer C): unknown; + } + ) ? + A | B | C + : T extends ( + { (...args: infer A): unknown; (...args: infer B): unknown; } - ? A | B - : T extends (...args: infer A) => unknown - ? A + ) ? + A | B + : T extends (...args: infer A) => unknown ? A : never; - +/* eslint-disable */ /** * These imports attempt to get types from a parent package's dependencies. * Unresolved bare specifiers can trigger [automatic type acquisition][1] in some projects, which @@ -57,19 +63,19 @@ type OverloadedParameters = T extends { * * [1]: https://www.typescriptlang.org/tsconfig/#typeAcquisition */ -/** @ts-ignore For users with \@types/node */ /* prettier-ignore */ +/** @ts-ignore For users with \@types/node */ type UndiciTypesRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with undici */ /* prettier-ignore */ +/** @ts-ignore For users with undici */ type UndiciRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with \@types/bun */ /* prettier-ignore */ +/** @ts-ignore For users with \@types/bun */ type BunRequestInit = globalThis.FetchRequestInit; -/** @ts-ignore For users with node-fetch@2 */ /* prettier-ignore */ +/** @ts-ignore For users with node-fetch@2 */ type NodeFetch2RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ /* prettier-ignore */ +/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ type NodeFetch3RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users who use Deno */ /* prettier-ignore */ +/** @ts-ignore For users who use Deno */ type FetchRequestInit = NonNullable[1]>; - +/* eslint-enable */ type RequestInits = | NotAny diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts index ab972230..b6662952 100644 --- a/src/internal/utils/log.ts +++ b/src/internal/utils/log.ts @@ -4,7 +4,7 @@ import { hasOwn } from './values'; import { type Writer } from '../../client'; import { RequestOptions } from '../request-options'; -type LogFn = (message: string, ...rest: unknown[]) => void +type LogFn = (message: string, ...rest: unknown[]) => void; export type Logger = { error: LogFn; warn: LogFn; @@ -21,14 +21,22 @@ const levelNumbers = { debug: 500, }; -export const parseLogLevel = (maybeLevel: string | undefined, sourceName: string, client: Writer): LogLevel | undefined => { +export const parseLogLevel = ( + maybeLevel: string | undefined, + sourceName: string, + client: Writer, +): LogLevel | undefined => { if (!maybeLevel) { return undefined; } if (hasOwn(levelNumbers, maybeLevel)) { return maybeLevel; - }; - loggerFor(client).warn(`${sourceName} was set to ${JSON.stringify(maybeLevel)}, expected one of ${JSON.stringify(Object.keys(levelNumbers))}`); + } + loggerFor(client).warn( + `${sourceName} was set to ${JSON.stringify(maybeLevel)}, expected one of ${JSON.stringify( + Object.keys(levelNumbers), + )}`, + ); return undefined; }; @@ -89,11 +97,24 @@ export const formatRequestDetails = (details: { body?: unknown; }) => { if (details.options) { - details.options = {...details.options}; + details.options = { ...details.options }; delete details.options['headers']; // redundant + leaks internals } if (details.headers) { - details.headers = Object.fromEntries((details.headers instanceof Headers ? [...details.headers] : Object.entries(details.headers)).map(([name, value]) => [name, name.toLowerCase() === 'authorization' || name.toLowerCase() === 'cookie' || name.toLowerCase() === 'set-cookie' ? '***' : value])) + details.headers = Object.fromEntries( + (details.headers instanceof Headers ? [...details.headers] : Object.entries(details.headers)).map( + ([name, value]) => [ + name, + ( + name.toLowerCase() === 'authorization' || + name.toLowerCase() === 'cookie' || + name.toLowerCase() === 'set-cookie' + ) ? + '***' + : value, + ], + ), + ); } if ('retryOfRequestLogID' in details) { if (details.retryOfRequestLogID) { @@ -101,5 +122,5 @@ export const formatRequestDetails = (details: { } delete details.retryOfRequestLogID; } - return details -} + return details; +}; diff --git a/src/internal/utils/uuid.ts b/src/internal/utils/uuid.ts index 53708ba6..b0e53aaf 100644 --- a/src/internal/utils/uuid.ts +++ b/src/internal/utils/uuid.ts @@ -10,10 +10,8 @@ export let uuid4 = function () { return crypto.randomUUID(); } const u8 = new Uint8Array(1); - const randomByte = crypto - ? () => crypto.getRandomValues(u8)[0]! - : () => (Math.random() * 0xff) & 0xff; - return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c) => + const randomByte = crypto ? () => crypto.getRandomValues(u8)[0]! : () => (Math.random() * 0xff) & 0xff; + return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, (c) => (+c ^ (randomByte() & (15 >> (+c / 4)))).toString(16), ); -} +}; diff --git a/src/pagination.ts b/src/pagination.ts index e1e5d091..90bf015e 100644 --- a/src/pagination.ts +++ b/src/pagination.ts @@ -1,2 +1,2 @@ /** @deprecated Import from ./core/pagination instead */ -export * from "./core/pagination" \ No newline at end of file +export * from './core/pagination'; diff --git a/src/resource.ts b/src/resource.ts index 57a27a94..363e3516 100644 --- a/src/resource.ts +++ b/src/resource.ts @@ -1,2 +1,2 @@ /** @deprecated Import from ./core/resource instead */ -export * from "./core/resource" \ No newline at end of file +export * from './core/resource'; diff --git a/src/resources/applications/applications.ts b/src/resources/applications/applications.ts index 15a52305..60fa6fc8 100644 --- a/src/resources/applications/applications.ts +++ b/src/resources/applications/applications.ts @@ -5,7 +5,16 @@ import * as ApplicationsAPI from './applications'; import * as GraphsAPI from './graphs'; import { ApplicationGraphsResponse, GraphUpdateParams, Graphs } from './graphs'; import * as JobsAPI from './jobs'; -import { ApplicationGenerateAsyncResponse, ApplicationGenerateAsyncResponsesApplicationJobsOffset, ApplicationJobsListResponse, JobCreateParams, JobCreateResponse, JobListParams, JobRetryResponse, Jobs } from './jobs'; +import { + ApplicationGenerateAsyncResponse, + ApplicationGenerateAsyncResponsesApplicationJobsOffset, + ApplicationJobsListResponse, + JobCreateParams, + JobCreateResponse, + JobListParams, + JobRetryResponse, + Jobs, +} from './jobs'; import { APIPromise } from '../../core/api-promise'; import { CursorPage, type CursorPageParams, PagePromise } from '../../core/pagination'; import { Stream } from '../../core/streaming'; @@ -28,23 +37,51 @@ export class Applications extends APIResource { * Retrieves a paginated list of no-code agents (formerly called no-code * applications) with optional filtering and sorting capabilities. */ - list(query: ApplicationListParams | null | undefined = {}, options?: RequestOptions): PagePromise { - return this._client.getAPIList('/v1/applications', CursorPage, { query, ...options }); + list( + query: ApplicationListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/v1/applications', CursorPage, { + query, + ...options, + }); } /** * Generate content from an existing no-code agent (formerly called no-code * applications) with inputs. */ - generateContent(applicationID: string, body: ApplicationGenerateContentParamsNonStreaming, options?: RequestOptions): APIPromise - generateContent(applicationID: string, body: ApplicationGenerateContentParamsStreaming, options?: RequestOptions): APIPromise> - generateContent(applicationID: string, body: ApplicationGenerateContentParamsBase, options?: RequestOptions): APIPromise | ApplicationGenerateContentResponse> - generateContent(applicationID: string, body: ApplicationGenerateContentParams, options?: RequestOptions): APIPromise | APIPromise> { - return this._client.post(path`/v1/applications/${applicationID}`, { body, ...options, stream: body.stream ?? false }) as APIPromise | APIPromise>; + generateContent( + applicationID: string, + body: ApplicationGenerateContentParamsNonStreaming, + options?: RequestOptions, + ): APIPromise; + generateContent( + applicationID: string, + body: ApplicationGenerateContentParamsStreaming, + options?: RequestOptions, + ): APIPromise>; + generateContent( + applicationID: string, + body: ApplicationGenerateContentParamsBase, + options?: RequestOptions, + ): APIPromise | ApplicationGenerateContentResponse>; + generateContent( + applicationID: string, + body: ApplicationGenerateContentParams, + options?: RequestOptions, + ): APIPromise | APIPromise> { + return this._client.post(path`/v1/applications/${applicationID}`, { + body, + ...options, + stream: body.stream ?? false, + }) as + | APIPromise + | APIPromise>; } } -export type ApplicationListResponsesCursorPage = CursorPage +export type ApplicationListResponsesCursorPage = CursorPage; export interface ApplicationGenerateContentChunk { delta: ApplicationGenerateContentChunk.Delta; @@ -174,7 +211,11 @@ export namespace ApplicationRetrieveResponse { /** * Type-specific configuration options for input fields. */ - options?: Input.ApplicationInputDropdownOptions | Input.ApplicationInputFileOptions | Input.ApplicationInputMediaOptions | Input.ApplicationInputTextOptions; + options?: + | Input.ApplicationInputDropdownOptions + | Input.ApplicationInputFileOptions + | Input.ApplicationInputMediaOptions + | Input.ApplicationInputTextOptions; } export namespace Input { @@ -324,7 +365,11 @@ export namespace ApplicationListResponse { /** * Type-specific configuration options for input fields. */ - options?: Input.ApplicationInputDropdownOptions | Input.ApplicationInputFileOptions | Input.ApplicationInputMediaOptions | Input.ApplicationInputTextOptions; + options?: + | Input.ApplicationInputDropdownOptions + | Input.ApplicationInputFileOptions + | Input.ApplicationInputMediaOptions + | Input.ApplicationInputTextOptions; } export namespace Input { @@ -417,7 +462,9 @@ export interface ApplicationListParams extends CursorPageParams { type?: 'generation'; } -export type ApplicationGenerateContentParams = ApplicationGenerateContentParamsNonStreaming | ApplicationGenerateContentParamsStreaming +export type ApplicationGenerateContentParams = + | ApplicationGenerateContentParamsNonStreaming + | ApplicationGenerateContentParamsStreaming; export interface ApplicationGenerateContentParamsBase { inputs: Array; @@ -451,8 +498,10 @@ export namespace ApplicationGenerateContentParams { value: Array; } - export type ApplicationGenerateContentParamsNonStreaming = ApplicationsAPI.ApplicationGenerateContentParamsNonStreaming - export type ApplicationGenerateContentParamsStreaming = ApplicationsAPI.ApplicationGenerateContentParamsStreaming + export type ApplicationGenerateContentParamsNonStreaming = + ApplicationsAPI.ApplicationGenerateContentParamsNonStreaming; + export type ApplicationGenerateContentParamsStreaming = + ApplicationsAPI.ApplicationGenerateContentParamsStreaming; } export interface ApplicationGenerateContentParamsNonStreaming extends ApplicationGenerateContentParamsBase { @@ -484,7 +533,7 @@ export declare namespace Applications { type ApplicationListParams as ApplicationListParams, type ApplicationGenerateContentParams as ApplicationGenerateContentParams, type ApplicationGenerateContentParamsNonStreaming as ApplicationGenerateContentParamsNonStreaming, - type ApplicationGenerateContentParamsStreaming as ApplicationGenerateContentParamsStreaming + type ApplicationGenerateContentParamsStreaming as ApplicationGenerateContentParamsStreaming, }; export { @@ -495,12 +544,12 @@ export declare namespace Applications { type JobRetryResponse as JobRetryResponse, type ApplicationGenerateAsyncResponsesApplicationJobsOffset as ApplicationGenerateAsyncResponsesApplicationJobsOffset, type JobCreateParams as JobCreateParams, - type JobListParams as JobListParams + type JobListParams as JobListParams, }; export { Graphs as Graphs, type ApplicationGraphsResponse as ApplicationGraphsResponse, - type GraphUpdateParams as GraphUpdateParams + type GraphUpdateParams as GraphUpdateParams, }; } diff --git a/src/resources/applications/graphs.ts b/src/resources/applications/graphs.ts index 4f592201..5a3f5b0b 100644 --- a/src/resources/applications/graphs.ts +++ b/src/resources/applications/graphs.ts @@ -9,7 +9,11 @@ export class Graphs extends APIResource { /** * Updates the list of Knowledge Graphs associated with a no-code chat agent. */ - update(applicationID: string, body: GraphUpdateParams, options?: RequestOptions): APIPromise { + update( + applicationID: string, + body: GraphUpdateParams, + options?: RequestOptions, + ): APIPromise { return this._client.put(path`/v1/applications/${applicationID}/graphs`, { body, ...options }); } @@ -41,6 +45,6 @@ export interface GraphUpdateParams { export declare namespace Graphs { export { type ApplicationGraphsResponse as ApplicationGraphsResponse, - type GraphUpdateParams as GraphUpdateParams + type GraphUpdateParams as GraphUpdateParams, }; } diff --git a/src/resources/applications/index.ts b/src/resources/applications/index.ts index 9684db79..da90190f 100644 --- a/src/resources/applications/index.ts +++ b/src/resources/applications/index.ts @@ -1,5 +1,25 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -export { Applications, type ApplicationGenerateContentChunk, type ApplicationGenerateContentResponse, type ApplicationRetrieveResponse, type ApplicationListResponse, type ApplicationListParams, type ApplicationGenerateContentParams, type ApplicationGenerateContentParamsNonStreaming, type ApplicationGenerateContentParamsStreaming, type ApplicationListResponsesCursorPage } from './applications';; -export { Graphs, type ApplicationGraphsResponse, type GraphUpdateParams } from './graphs';; -export { Jobs, type ApplicationGenerateAsyncResponse, type ApplicationJobsListResponse, type JobCreateResponse, type JobRetryResponse, type JobCreateParams, type JobListParams, type ApplicationGenerateAsyncResponsesApplicationJobsOffset } from './jobs';; +export { + Applications, + type ApplicationGenerateContentChunk, + type ApplicationGenerateContentResponse, + type ApplicationRetrieveResponse, + type ApplicationListResponse, + type ApplicationListParams, + type ApplicationGenerateContentParams, + type ApplicationGenerateContentParamsNonStreaming, + type ApplicationGenerateContentParamsStreaming, + type ApplicationListResponsesCursorPage, +} from './applications'; +export { Graphs, type ApplicationGraphsResponse, type GraphUpdateParams } from './graphs'; +export { + Jobs, + type ApplicationGenerateAsyncResponse, + type ApplicationJobsListResponse, + type JobCreateResponse, + type JobRetryResponse, + type JobCreateParams, + type JobListParams, + type ApplicationGenerateAsyncResponsesApplicationJobsOffset, +} from './jobs'; diff --git a/src/resources/applications/jobs.ts b/src/resources/applications/jobs.ts index 80667e69..20fb29aa 100644 --- a/src/resources/applications/jobs.ts +++ b/src/resources/applications/jobs.ts @@ -12,7 +12,11 @@ export class Jobs extends APIResource { * Generate content asynchronously from an existing no-code agent (formerly called * no-code applications) with inputs. */ - create(applicationID: string, body: JobCreateParams, options?: RequestOptions): APIPromise { + create( + applicationID: string, + body: JobCreateParams, + options?: RequestOptions, + ): APIPromise { return this._client.post(path`/v1/applications/${applicationID}/jobs`, { body, ...options }); } @@ -27,8 +31,16 @@ export class Jobs extends APIResource { * Retrieve all jobs created via the async API, linked to the provided application * ID (or alias). */ - list(applicationID: string, query: JobListParams | null | undefined = {}, options?: RequestOptions): PagePromise { - return this._client.getAPIList(path`/v1/applications/${applicationID}/jobs`, ApplicationJobsOffset, { query, ...options }); + list( + applicationID: string, + query: JobListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList( + path`/v1/applications/${applicationID}/jobs`, + ApplicationJobsOffset, + { query, ...options }, + ); } /** @@ -40,7 +52,8 @@ export class Jobs extends APIResource { } } -export type ApplicationGenerateAsyncResponsesApplicationJobsOffset = ApplicationJobsOffset +export type ApplicationGenerateAsyncResponsesApplicationJobsOffset = + ApplicationJobsOffset; export interface ApplicationGenerateAsyncResponse { /** @@ -188,6 +201,6 @@ export declare namespace Jobs { type JobRetryResponse as JobRetryResponse, type ApplicationGenerateAsyncResponsesApplicationJobsOffset as ApplicationGenerateAsyncResponsesApplicationJobsOffset, type JobCreateParams as JobCreateParams, - type JobListParams as JobListParams + type JobListParams as JobListParams, }; } diff --git a/src/resources/chat.ts b/src/resources/chat.ts index be9a8d6b..ec2a4da6 100644 --- a/src/resources/chat.ts +++ b/src/resources/chat.ts @@ -17,11 +17,19 @@ export class Chat extends APIResource { * below is for non-streaming. To learn about streaming responses, see the * [chat completion guide](https://dev.writer.com/home/chat-completion). */ - chat(body: ChatChatParamsNonStreaming, options?: RequestOptions): APIPromise - chat(body: ChatChatParamsStreaming, options?: RequestOptions): APIPromise> - chat(body: ChatChatParamsBase, options?: RequestOptions): APIPromise | ChatCompletion> - chat(body: ChatChatParams, options?: RequestOptions): APIPromise | APIPromise> { - return this._client.post('/v1/chat', { body, ...options, stream: body.stream ?? false }) as APIPromise | APIPromise>; + chat(body: ChatChatParamsNonStreaming, options?: RequestOptions): APIPromise; + chat(body: ChatChatParamsStreaming, options?: RequestOptions): APIPromise>; + chat( + body: ChatChatParamsBase, + options?: RequestOptions, + ): APIPromise | ChatCompletion>; + chat( + body: ChatChatParams, + options?: RequestOptions, + ): APIPromise | APIPromise> { + return this._client.post('/v1/chat', { body, ...options, stream: body.stream ?? false }) as + | APIPromise + | APIPromise>; } /** @@ -610,7 +618,7 @@ export namespace ChatCompletionUsage { } } -export type ChatChatParams = ChatChatParamsNonStreaming | ChatChatParamsStreaming +export type ChatChatParams = ChatChatParamsNonStreaming | ChatChatParamsStreaming; export interface ChatChatParamsBase { /** @@ -825,8 +833,8 @@ export namespace ChatChatParams { include_usage: boolean; } - export type ChatChatParamsNonStreaming = ChatAPI.ChatChatParamsNonStreaming - export type ChatChatParamsStreaming = ChatAPI.ChatChatParamsStreaming + export type ChatChatParamsNonStreaming = ChatAPI.ChatChatParamsNonStreaming; + export type ChatChatParamsStreaming = ChatAPI.ChatChatParamsStreaming; } export interface ChatChatParamsNonStreaming extends ChatChatParamsBase { diff --git a/src/resources/completions.ts b/src/resources/completions.ts index 22236809..3733da13 100644 --- a/src/resources/completions.ts +++ b/src/resources/completions.ts @@ -20,11 +20,22 @@ export class Completions extends APIResource { * }); * ``` */ - create(body: CompletionCreateParamsNonStreaming, options?: RequestOptions): APIPromise - create(body: CompletionCreateParamsStreaming, options?: RequestOptions): APIPromise> - create(body: CompletionCreateParamsBase, options?: RequestOptions): APIPromise | Completion> - create(body: CompletionCreateParams, options?: RequestOptions): APIPromise | APIPromise> { - return this._client.post('/v1/completions', { body, ...options, stream: body.stream ?? false }) as APIPromise | APIPromise>; + create(body: CompletionCreateParamsNonStreaming, options?: RequestOptions): APIPromise; + create( + body: CompletionCreateParamsStreaming, + options?: RequestOptions, + ): APIPromise>; + create( + body: CompletionCreateParamsBase, + options?: RequestOptions, + ): APIPromise | Completion>; + create( + body: CompletionCreateParams, + options?: RequestOptions, + ): APIPromise | APIPromise> { + return this._client.post('/v1/completions', { body, ...options, stream: body.stream ?? false }) as + | APIPromise + | APIPromise>; } } @@ -116,7 +127,7 @@ export interface CompletionParams { top_p?: number; } -export type CompletionCreateParams = CompletionCreateParamsNonStreaming | CompletionCreateParamsStreaming +export type CompletionCreateParams = CompletionCreateParamsNonStreaming | CompletionCreateParamsStreaming; export interface CompletionCreateParamsBase { /** @@ -177,8 +188,8 @@ export interface CompletionCreateParamsBase { } export namespace CompletionCreateParams { - export type CompletionCreateParamsNonStreaming = CompletionsAPI.CompletionCreateParamsNonStreaming - export type CompletionCreateParamsStreaming = CompletionsAPI.CompletionCreateParamsStreaming + export type CompletionCreateParamsNonStreaming = CompletionsAPI.CompletionCreateParamsNonStreaming; + export type CompletionCreateParamsStreaming = CompletionsAPI.CompletionCreateParamsStreaming; } export interface CompletionCreateParamsNonStreaming extends CompletionCreateParamsBase { @@ -206,6 +217,6 @@ export declare namespace Completions { type CompletionParams as CompletionParams, type CompletionCreateParams as CompletionCreateParams, type CompletionCreateParamsNonStreaming as CompletionCreateParamsNonStreaming, - type CompletionCreateParamsStreaming as CompletionCreateParamsStreaming + type CompletionCreateParamsStreaming as CompletionCreateParamsStreaming, }; } diff --git a/src/resources/files.ts b/src/resources/files.ts index 514dcda6..e5214069 100644 --- a/src/resources/files.ts +++ b/src/resources/files.ts @@ -22,7 +22,10 @@ export class Files extends APIResource { * Retrieve a paginated list of files with optional filtering by status, graph * association, and file type. */ - list(query: FileListParams | null | undefined = {}, options?: RequestOptions): PagePromise { + list( + query: FileListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { return this._client.getAPIList('/v1/files', CursorPage, { query, ...options }); } @@ -38,7 +41,11 @@ export class Files extends APIResource { * in the appropriate MIME type. */ download(fileID: string, options?: RequestOptions): APIPromise { - return this._client.get(path`/v1/files/${fileID}/download`, { ...options, headers: buildHeaders([{Accept: 'application/octet-stream'}, options?.headers]), __binaryResponse: true }); + return this._client.get(path`/v1/files/${fileID}/download`, { + ...options, + headers: buildHeaders([{ Accept: 'application/octet-stream' }, options?.headers]), + __binaryResponse: true, + }); } /** @@ -64,16 +71,15 @@ export class Files extends APIResource { query: { graphId }, body: content, ...options, - headers: { - 'Content-Type': contentType, - 'Content-Disposition': contentDisposition, - ...options?.headers, - }, + headers: buildHeaders([ + { 'Content-Type': contentType, 'Content-Disposition': contentDisposition }, + options?.headers, + ]), }); } } -export type FilesCursorPage = CursorPage +export type FilesCursorPage = CursorPage; export interface File { /** @@ -201,6 +207,6 @@ export declare namespace Files { type FilesCursorPage as FilesCursorPage, type FileListParams as FileListParams, type FileRetryParams as FileRetryParams, - type FileUploadParams as FileUploadParams + type FileUploadParams as FileUploadParams, }; } diff --git a/src/resources/graphs.ts b/src/resources/graphs.ts index 06b4612e..a7f13b96 100644 --- a/src/resources/graphs.ts +++ b/src/resources/graphs.ts @@ -28,14 +28,21 @@ export class Graphs extends APIResource { /** * Update the name and description of a Knowledge Graph. */ - update(graphID: string, body: GraphUpdateParams, options?: RequestOptions): APIPromise { + update( + graphID: string, + body: GraphUpdateParams, + options?: RequestOptions, + ): APIPromise { return this._client.put(path`/v1/graphs/${graphID}`, { body, ...options }); } /** * Retrieve a list of Knowledge Graphs. */ - list(query: GraphListParams | null | undefined = {}, options?: RequestOptions): PagePromise { + list( + query: GraphListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { return this._client.getAPIList('/v1/graphs', CursorPage, { query, ...options }); } @@ -49,30 +56,49 @@ export class Graphs extends APIResource { /** * Add a file to a Knowledge Graph. */ - addFileToGraph(graphID: string, body: GraphAddFileToGraphParams, options?: RequestOptions): APIPromise { + addFileToGraph( + graphID: string, + body: GraphAddFileToGraphParams, + options?: RequestOptions, + ): APIPromise { return this._client.post(path`/v1/graphs/${graphID}/file`, { body, ...options }); } /** * Ask a question to specified Knowledge Graphs. */ - question(body: GraphQuestionParamsNonStreaming, options?: RequestOptions): APIPromise - question(body: GraphQuestionParamsStreaming, options?: RequestOptions): APIPromise> - question(body: GraphQuestionParamsBase, options?: RequestOptions): APIPromise | Question> - question(body: GraphQuestionParams, options?: RequestOptions): APIPromise | APIPromise> { - return this._client.post('/v1/graphs/question', { body, ...options, stream: body.stream ?? false }) as APIPromise | APIPromise>; + question(body: GraphQuestionParamsNonStreaming, options?: RequestOptions): APIPromise; + question( + body: GraphQuestionParamsStreaming, + options?: RequestOptions, + ): APIPromise>; + question( + body: GraphQuestionParamsBase, + options?: RequestOptions, + ): APIPromise | Question>; + question( + body: GraphQuestionParams, + options?: RequestOptions, + ): APIPromise | APIPromise> { + return this._client.post('/v1/graphs/question', { body, ...options, stream: body.stream ?? false }) as + | APIPromise + | APIPromise>; } /** * Remove a file from a Knowledge Graph. */ - removeFileFromGraph(fileID: string, params: GraphRemoveFileFromGraphParams, options?: RequestOptions): APIPromise { - const { graph_id } = params + removeFileFromGraph( + fileID: string, + params: GraphRemoveFileFromGraphParams, + options?: RequestOptions, + ): APIPromise { + const { graph_id } = params; return this._client.delete(path`/v1/graphs/${graph_id}/file/${fileID}`, options); } } -export type GraphsCursorPage = CursorPage +export type GraphsCursorPage = CursorPage; export interface Graph { /** @@ -177,7 +203,12 @@ export namespace Graph { /** * The type of error that occurred during processing, if any. */ - error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; + error_type?: + | 'invalid_url' + | 'not_searchable' + | 'not_found' + | 'paywall_or_login_page' + | 'unexpected_error'; } } } @@ -374,7 +405,12 @@ export namespace GraphCreateResponse { /** * The type of error that occurred during processing, if any. */ - error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; + error_type?: + | 'invalid_url' + | 'not_searchable' + | 'not_found' + | 'paywall_or_login_page' + | 'unexpected_error'; } } } @@ -442,7 +478,12 @@ export namespace GraphUpdateResponse { /** * The type of error that occurred during processing, if any. */ - error_type?: 'invalid_url' | 'not_searchable' | 'not_found' | 'paywall_or_login_page' | 'unexpected_error'; + error_type?: + | 'invalid_url' + | 'not_searchable' + | 'not_found' + | 'paywall_or_login_page' + | 'unexpected_error'; } } } @@ -546,7 +587,7 @@ export interface GraphAddFileToGraphParams { file_id: string; } -export type GraphQuestionParams = GraphQuestionParamsNonStreaming | GraphQuestionParamsStreaming +export type GraphQuestionParams = GraphQuestionParamsNonStreaming | GraphQuestionParamsStreaming; export interface GraphQuestionParamsBase { /** @@ -649,8 +690,8 @@ export namespace GraphQuestionParams { semantic_threshold?: number; } - export type GraphQuestionParamsNonStreaming = GraphsAPI.GraphQuestionParamsNonStreaming - export type GraphQuestionParamsStreaming = GraphsAPI.GraphQuestionParamsStreaming + export type GraphQuestionParamsNonStreaming = GraphsAPI.GraphQuestionParamsNonStreaming; + export type GraphQuestionParamsStreaming = GraphsAPI.GraphQuestionParamsStreaming; } export interface GraphQuestionParamsNonStreaming extends GraphQuestionParamsBase { @@ -695,6 +736,6 @@ export declare namespace Graphs { type GraphQuestionParams as GraphQuestionParams, type GraphQuestionParamsNonStreaming as GraphQuestionParamsNonStreaming, type GraphQuestionParamsStreaming as GraphQuestionParamsStreaming, - type GraphRemoveFileFromGraphParams as GraphRemoveFileFromGraphParams + type GraphRemoveFileFromGraphParams as GraphRemoveFileFromGraphParams, }; } diff --git a/src/resources/index.ts b/src/resources/index.ts index 6fb12517..528a38ec 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -1,12 +1,80 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -export * from './shared';; -export { Applications, type ApplicationGenerateContentChunk, type ApplicationGenerateContentResponse, type ApplicationRetrieveResponse, type ApplicationListResponse, type ApplicationListParams, type ApplicationGenerateContentParams, type ApplicationGenerateContentParamsNonStreaming, type ApplicationGenerateContentParamsStreaming, type ApplicationListResponsesCursorPage } from './applications/applications';; -export { Chat, type ChatCompletion, type ChatCompletionChoice, type ChatCompletionChunk, type ChatCompletionMessage, type ChatCompletionParams, type ChatCompletionUsage, type ChatChatParams, type ChatChatParamsNonStreaming, type ChatChatParamsStreaming } from './chat';; -export { Completions, type Completion, type CompletionChunk, type CompletionParams, type CompletionCreateParams, type CompletionCreateParamsNonStreaming, type CompletionCreateParamsStreaming } from './completions';; -export { Files, type File, type FileDeleteResponse, type FileRetryResponse, type FileListParams, type FileRetryParams, type FileUploadParams, type FilesCursorPage } from './files';; -export { Graphs, type Graph, type Question, type QuestionResponseChunk, type GraphCreateResponse, type GraphUpdateResponse, type GraphDeleteResponse, type GraphRemoveFileFromGraphResponse, type GraphCreateParams, type GraphUpdateParams, type GraphListParams, type GraphAddFileToGraphParams, type GraphQuestionParams, type GraphQuestionParamsNonStreaming, type GraphQuestionParamsStreaming, type GraphRemoveFileFromGraphParams, type GraphsCursorPage } from './graphs';; -export { Models, type ModelListResponse } from './models';; -export { Tools, type ToolParsePdfResponse, type ToolWebSearchResponse, type ToolParsePdfParams, type ToolWebSearchParams } from './tools';; -export { Translation, type TranslationRequest, type TranslationResponse, type TranslationTranslateParams } from './translation';; -export { Vision, type VisionRequest, type VisionResponse, type VisionAnalyzeParams } from './vision';; +export * from './shared'; +export { + Applications, + type ApplicationGenerateContentChunk, + type ApplicationGenerateContentResponse, + type ApplicationRetrieveResponse, + type ApplicationListResponse, + type ApplicationListParams, + type ApplicationGenerateContentParams, + type ApplicationGenerateContentParamsNonStreaming, + type ApplicationGenerateContentParamsStreaming, + type ApplicationListResponsesCursorPage, +} from './applications/applications'; +export { + Chat, + type ChatCompletion, + type ChatCompletionChoice, + type ChatCompletionChunk, + type ChatCompletionMessage, + type ChatCompletionParams, + type ChatCompletionUsage, + type ChatChatParams, + type ChatChatParamsNonStreaming, + type ChatChatParamsStreaming, +} from './chat'; +export { + Completions, + type Completion, + type CompletionChunk, + type CompletionParams, + type CompletionCreateParams, + type CompletionCreateParamsNonStreaming, + type CompletionCreateParamsStreaming, +} from './completions'; +export { + Files, + type File, + type FileDeleteResponse, + type FileRetryResponse, + type FileListParams, + type FileRetryParams, + type FileUploadParams, + type FilesCursorPage, +} from './files'; +export { + Graphs, + type Graph, + type Question, + type QuestionResponseChunk, + type GraphCreateResponse, + type GraphUpdateResponse, + type GraphDeleteResponse, + type GraphRemoveFileFromGraphResponse, + type GraphCreateParams, + type GraphUpdateParams, + type GraphListParams, + type GraphAddFileToGraphParams, + type GraphQuestionParams, + type GraphQuestionParamsNonStreaming, + type GraphQuestionParamsStreaming, + type GraphRemoveFileFromGraphParams, + type GraphsCursorPage, +} from './graphs'; +export { Models, type ModelListResponse } from './models'; +export { + Tools, + type ToolParsePdfResponse, + type ToolWebSearchResponse, + type ToolParsePdfParams, + type ToolWebSearchParams, +} from './tools'; +export { + Translation, + type TranslationRequest, + type TranslationResponse, + type TranslationTranslateParams, +} from './translation'; +export { Vision, type VisionRequest, type VisionResponse, type VisionAnalyzeParams } from './vision'; diff --git a/src/resources/models.ts b/src/resources/models.ts index 1214b16f..f19b98e9 100644 --- a/src/resources/models.ts +++ b/src/resources/models.ts @@ -42,7 +42,5 @@ export namespace ModelListResponse { } export declare namespace Models { - export { - type ModelListResponse as ModelListResponse - }; + export { type ModelListResponse as ModelListResponse }; } diff --git a/src/resources/shared.ts b/src/resources/shared.ts index dd8b64ff..c852af4e 100644 --- a/src/resources/shared.ts +++ b/src/resources/shared.ts @@ -39,7 +39,7 @@ export interface FunctionDefinition { /** * The parameters of the function. */ -export type FunctionParams = { [key: string]: unknown } +export type FunctionParams = { [key: string]: unknown }; export interface GraphData { /** @@ -256,7 +256,13 @@ export interface ToolChoiceString { * A tool that uses Palmyra Translate to translate text. Note that this tool does * not stream results. The response is returned after the translation is complete. */ -export type ToolParam = ToolParam.FunctionTool | ToolParam.GraphTool | ToolParam.LlmTool | ToolParam.TranslationTool | ToolParam.VisionTool | ToolParam.WebSearchTool +export type ToolParam = + | ToolParam.FunctionTool + | ToolParam.GraphTool + | ToolParam.LlmTool + | ToolParam.TranslationTool + | ToolParam.VisionTool + | ToolParam.WebSearchTool; export namespace ToolParam { export interface FunctionTool { diff --git a/src/resources/tools.ts b/src/resources/tools.ts index 838b5965..b6bf9568 100644 --- a/src/resources/tools.ts +++ b/src/resources/tools.ts @@ -11,7 +11,11 @@ export class Tools extends APIResource { * * @deprecated Will be removed in a future release. A replacement PDF parsing tool for chat completions is planned; see documentation at dev.writer.com for more information. */ - parsePdf(fileID: string, body: ToolParsePdfParams, options?: RequestOptions): APIPromise { + parsePdf( + fileID: string, + body: ToolParsePdfParams, + options?: RequestOptions, + ): APIPromise { return this._client.post(path`/v1/tools/pdf-parser/${fileID}`, { body, ...options }); } @@ -84,7 +88,173 @@ export interface ToolWebSearchParams { * Localizes search results to a specific country. Only applies to general topic * searches. */ - country?: 'afghanistan' | 'albania' | 'algeria' | 'andorra' | 'angola' | 'argentina' | 'armenia' | 'australia' | 'austria' | 'azerbaijan' | 'bahamas' | 'bahrain' | 'bangladesh' | 'barbados' | 'belarus' | 'belgium' | 'belize' | 'benin' | 'bhutan' | 'bolivia' | 'bosnia and herzegovina' | 'botswana' | 'brazil' | 'brunei' | 'bulgaria' | 'burkina faso' | 'burundi' | 'cambodia' | 'cameroon' | 'canada' | 'cape verde' | 'central african republic' | 'chad' | 'chile' | 'china' | 'colombia' | 'comoros' | 'congo' | 'costa rica' | 'croatia' | 'cuba' | 'cyprus' | 'czech republic' | 'denmark' | 'djibouti' | 'dominican republic' | 'ecuador' | 'egypt' | 'el salvador' | 'equatorial guinea' | 'eritrea' | 'estonia' | 'ethiopia' | 'fiji' | 'finland' | 'france' | 'gabon' | 'gambia' | 'georgia' | 'germany' | 'ghana' | 'greece' | 'guatemala' | 'guinea' | 'haiti' | 'honduras' | 'hungary' | 'iceland' | 'india' | 'indonesia' | 'iran' | 'iraq' | 'ireland' | 'israel' | 'italy' | 'jamaica' | 'japan' | 'jordan' | 'kazakhstan' | 'kenya' | 'kuwait' | 'kyrgyzstan' | 'latvia' | 'lebanon' | 'lesotho' | 'liberia' | 'libya' | 'liechtenstein' | 'lithuania' | 'luxembourg' | 'madagascar' | 'malawi' | 'malaysia' | 'maldives' | 'mali' | 'malta' | 'mauritania' | 'mauritius' | 'mexico' | 'moldova' | 'monaco' | 'mongolia' | 'montenegro' | 'morocco' | 'mozambique' | 'myanmar' | 'namibia' | 'nepal' | 'netherlands' | 'new zealand' | 'nicaragua' | 'niger' | 'nigeria' | 'north korea' | 'north macedonia' | 'norway' | 'oman' | 'pakistan' | 'panama' | 'papua new guinea' | 'paraguay' | 'peru' | 'philippines' | 'poland' | 'portugal' | 'qatar' | 'romania' | 'russia' | 'rwanda' | 'saudi arabia' | 'senegal' | 'serbia' | 'singapore' | 'slovakia' | 'slovenia' | 'somalia' | 'south africa' | 'south korea' | 'south sudan' | 'spain' | 'sri lanka' | 'sudan' | 'sweden' | 'switzerland' | 'syria' | 'taiwan' | 'tajikistan' | 'tanzania' | 'thailand' | 'togo' | 'trinidad and tobago' | 'tunisia' | 'turkey' | 'turkmenistan' | 'uganda' | 'ukraine' | 'united arab emirates' | 'united kingdom' | 'united states' | 'uruguay' | 'uzbekistan' | 'venezuela' | 'vietnam' | 'yemen' | 'zambia' | 'zimbabwe'; + country?: + | 'afghanistan' + | 'albania' + | 'algeria' + | 'andorra' + | 'angola' + | 'argentina' + | 'armenia' + | 'australia' + | 'austria' + | 'azerbaijan' + | 'bahamas' + | 'bahrain' + | 'bangladesh' + | 'barbados' + | 'belarus' + | 'belgium' + | 'belize' + | 'benin' + | 'bhutan' + | 'bolivia' + | 'bosnia and herzegovina' + | 'botswana' + | 'brazil' + | 'brunei' + | 'bulgaria' + | 'burkina faso' + | 'burundi' + | 'cambodia' + | 'cameroon' + | 'canada' + | 'cape verde' + | 'central african republic' + | 'chad' + | 'chile' + | 'china' + | 'colombia' + | 'comoros' + | 'congo' + | 'costa rica' + | 'croatia' + | 'cuba' + | 'cyprus' + | 'czech republic' + | 'denmark' + | 'djibouti' + | 'dominican republic' + | 'ecuador' + | 'egypt' + | 'el salvador' + | 'equatorial guinea' + | 'eritrea' + | 'estonia' + | 'ethiopia' + | 'fiji' + | 'finland' + | 'france' + | 'gabon' + | 'gambia' + | 'georgia' + | 'germany' + | 'ghana' + | 'greece' + | 'guatemala' + | 'guinea' + | 'haiti' + | 'honduras' + | 'hungary' + | 'iceland' + | 'india' + | 'indonesia' + | 'iran' + | 'iraq' + | 'ireland' + | 'israel' + | 'italy' + | 'jamaica' + | 'japan' + | 'jordan' + | 'kazakhstan' + | 'kenya' + | 'kuwait' + | 'kyrgyzstan' + | 'latvia' + | 'lebanon' + | 'lesotho' + | 'liberia' + | 'libya' + | 'liechtenstein' + | 'lithuania' + | 'luxembourg' + | 'madagascar' + | 'malawi' + | 'malaysia' + | 'maldives' + | 'mali' + | 'malta' + | 'mauritania' + | 'mauritius' + | 'mexico' + | 'moldova' + | 'monaco' + | 'mongolia' + | 'montenegro' + | 'morocco' + | 'mozambique' + | 'myanmar' + | 'namibia' + | 'nepal' + | 'netherlands' + | 'new zealand' + | 'nicaragua' + | 'niger' + | 'nigeria' + | 'north korea' + | 'north macedonia' + | 'norway' + | 'oman' + | 'pakistan' + | 'panama' + | 'papua new guinea' + | 'paraguay' + | 'peru' + | 'philippines' + | 'poland' + | 'portugal' + | 'qatar' + | 'romania' + | 'russia' + | 'rwanda' + | 'saudi arabia' + | 'senegal' + | 'serbia' + | 'singapore' + | 'slovakia' + | 'slovenia' + | 'somalia' + | 'south africa' + | 'south korea' + | 'south sudan' + | 'spain' + | 'sri lanka' + | 'sudan' + | 'sweden' + | 'switzerland' + | 'syria' + | 'taiwan' + | 'tajikistan' + | 'tanzania' + | 'thailand' + | 'togo' + | 'trinidad and tobago' + | 'tunisia' + | 'turkey' + | 'turkmenistan' + | 'uganda' + | 'ukraine' + | 'united arab emirates' + | 'united kingdom' + | 'united states' + | 'uruguay' + | 'uzbekistan' + | 'venezuela' + | 'vietnam' + | 'yemen' + | 'zambia' + | 'zimbabwe'; /** * For news topic searches, specifies how many days of news coverage to include. @@ -160,6 +330,6 @@ export declare namespace Tools { type ToolParsePdfResponse as ToolParsePdfResponse, type ToolWebSearchResponse as ToolWebSearchResponse, type ToolParsePdfParams as ToolParsePdfParams, - type ToolWebSearchParams as ToolWebSearchParams + type ToolWebSearchParams as ToolWebSearchParams, }; } diff --git a/src/resources/translation.ts b/src/resources/translation.ts index cf345045..b5ce8c32 100644 --- a/src/resources/translation.ts +++ b/src/resources/translation.ts @@ -136,6 +136,6 @@ export declare namespace Translation { export { type TranslationRequest as TranslationRequest, type TranslationResponse as TranslationResponse, - type TranslationTranslateParams as TranslationTranslateParams + type TranslationTranslateParams as TranslationTranslateParams, }; } diff --git a/src/resources/vision.ts b/src/resources/vision.ts index b3ec114a..87544c76 100644 --- a/src/resources/vision.ts +++ b/src/resources/vision.ts @@ -124,6 +124,6 @@ export declare namespace Vision { export { type VisionRequest as VisionRequest, type VisionResponse as VisionResponse, - type VisionAnalyzeParams as VisionAnalyzeParams + type VisionAnalyzeParams as VisionAnalyzeParams, }; } diff --git a/src/streaming.ts b/src/streaming.ts index 17085360..9e6da106 100644 --- a/src/streaming.ts +++ b/src/streaming.ts @@ -1,2 +1,2 @@ /** @deprecated Import from ./core/streaming instead */ -export * from "./core/streaming" \ No newline at end of file +export * from './core/streaming'; diff --git a/src/uploads.ts b/src/uploads.ts index d5437085..b2ef6471 100644 --- a/src/uploads.ts +++ b/src/uploads.ts @@ -1,2 +1,2 @@ /** @deprecated Import from ./core/uploads instead */ -export * from "./core/uploads" \ No newline at end of file +export * from './core/uploads'; diff --git a/src/version.ts b/src/version.ts index c2755d49..1e17ebcc 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '3.0.0-rc.1';// x-release-please-version +export const VERSION = '3.0.0-rc.1'; // x-release-please-version diff --git a/tests/api-resources/applications/applications.test.ts b/tests/api-resources/applications/applications.test.ts index 5211d079..a3177bac 100644 --- a/tests/api-resources/applications/applications.test.ts +++ b/tests/api-resources/applications/applications.test.ts @@ -2,7 +2,10 @@ import Writer from 'writer-sdk'; -const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); +const client = new Writer({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); describe('resource applications', () => { test('retrieve', async () => { @@ -29,19 +32,24 @@ describe('resource applications', () => { test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.applications.list({ - after: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - before: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - limit: 0, - order: 'asc', - type: 'generation', - }, { path: '/_stainless_unknown_path' })) - .rejects - .toThrow(Writer.NotFoundError); + await expect( + client.applications.list( + { + after: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + before: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + limit: 0, + order: 'asc', + type: 'generation', + }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(Writer.NotFoundError); }); test('generateContent: only required params', async () => { - const responsePromise = client.applications.generateContent('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { inputs: [{ id: 'id', value: ['string'] }] }); + const responsePromise = client.applications.generateContent('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { + inputs: [{ id: 'id', value: ['string'] }], + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -52,6 +60,9 @@ describe('resource applications', () => { }); test('generateContent: required and optional params', async () => { - const response = await client.applications.generateContent('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { inputs: [{ id: 'id', value: ['string'] }], stream: false }); + const response = await client.applications.generateContent('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { + inputs: [{ id: 'id', value: ['string'] }], + stream: false, + }); }); }); diff --git a/tests/api-resources/applications/graphs.test.ts b/tests/api-resources/applications/graphs.test.ts index f97a392d..6edb71c0 100644 --- a/tests/api-resources/applications/graphs.test.ts +++ b/tests/api-resources/applications/graphs.test.ts @@ -2,11 +2,16 @@ import Writer from 'writer-sdk'; -const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); +const client = new Writer({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); describe('resource graphs', () => { test('update: only required params', async () => { - const responsePromise = client.applications.graphs.update('application_id', { graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] }); + const responsePromise = client.applications.graphs.update('application_id', { + graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -17,7 +22,9 @@ describe('resource graphs', () => { }); test('update: required and optional params', async () => { - const response = await client.applications.graphs.update('application_id', { graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'] }); + const response = await client.applications.graphs.update('application_id', { + graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], + }); }); test('list', async () => { diff --git a/tests/api-resources/applications/jobs.test.ts b/tests/api-resources/applications/jobs.test.ts index 0a270645..1b53c41e 100644 --- a/tests/api-resources/applications/jobs.test.ts +++ b/tests/api-resources/applications/jobs.test.ts @@ -2,11 +2,16 @@ import Writer from 'writer-sdk'; -const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); +const client = new Writer({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); describe('resource jobs', () => { test('create: only required params', async () => { - const responsePromise = client.applications.jobs.create('application_id', { inputs: [{ id: 'id', value: ['string'] }] }); + const responsePromise = client.applications.jobs.create('application_id', { + inputs: [{ id: 'id', value: ['string'] }], + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -17,7 +22,9 @@ describe('resource jobs', () => { }); test('create: required and optional params', async () => { - const response = await client.applications.jobs.create('application_id', { inputs: [{ id: 'id', value: ['string'] }] }); + const response = await client.applications.jobs.create('application_id', { + inputs: [{ id: 'id', value: ['string'] }], + }); }); test('retrieve', async () => { @@ -44,13 +51,17 @@ describe('resource jobs', () => { test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.applications.jobs.list('application_id', { - limit: 0, - offset: 0, - status: 'in_progress', - }, { path: '/_stainless_unknown_path' })) - .rejects - .toThrow(Writer.NotFoundError); + await expect( + client.applications.jobs.list( + 'application_id', + { + limit: 0, + offset: 0, + status: 'in_progress', + }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(Writer.NotFoundError); }); test('retry', async () => { diff --git a/tests/api-resources/chat.test.ts b/tests/api-resources/chat.test.ts index 9778f8d9..5094a0d3 100644 --- a/tests/api-resources/chat.test.ts +++ b/tests/api-resources/chat.test.ts @@ -2,7 +2,10 @@ import Writer from 'writer-sdk'; -const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); +const client = new Writer({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); describe('resource chat', () => { test('chat: only required params', async () => { @@ -18,62 +21,77 @@ describe('resource chat', () => { test('chat: required and optional params', async () => { const response = await client.chat.chat({ - messages: [{ - role: 'user', - content: 'string', - graph_data: { - references: { files: [{ - fileId: 'fileId', - score: 0, - text: 'text', - cite: 'cite', - page: 0, - }], web: [{ - score: 0, - text: 'text', - title: 'title', - url: 'https://example.com', - }] }, - sources: [{ file_id: 'file_id', snippet: 'snippet' }], - status: 'processing', - subqueries: [{ - answer: 'answer', - query: 'query', - sources: [{ file_id: 'file_id', snippet: 'snippet' }], - }], - }, - name: 'name', - refusal: 'refusal', - tool_call_id: 'tool_call_id', - tool_calls: [{ - id: 'id', - function: { arguments: 'arguments', name: 'name' }, - type: 'function', - index: 0, - }], - }], - model: 'model', - logprobs: true, - max_tokens: 0, - n: 0, - response_format: { - type: 'text', - json_schema: {}, - }, - stop: ['string'], - stream: false, - stream_options: { include_usage: true }, - temperature: 0, - tool_choice: { value: 'none' }, - tools: [{ - function: { - name: 'name', - description: 'description', - parameters: { foo: 'bar' }, - }, - type: 'function', - }], - top_p: 0, - }); + messages: [ + { + role: 'user', + content: 'string', + graph_data: { + references: { + files: [ + { + fileId: 'fileId', + score: 0, + text: 'text', + cite: 'cite', + page: 0, + }, + ], + web: [ + { + score: 0, + text: 'text', + title: 'title', + url: 'https://example.com', + }, + ], + }, + sources: [{ file_id: 'file_id', snippet: 'snippet' }], + status: 'processing', + subqueries: [ + { + answer: 'answer', + query: 'query', + sources: [{ file_id: 'file_id', snippet: 'snippet' }], + }, + ], + }, + name: 'name', + refusal: 'refusal', + tool_call_id: 'tool_call_id', + tool_calls: [ + { + id: 'id', + function: { arguments: 'arguments', name: 'name' }, + type: 'function', + index: 0, + }, + ], + }, + ], + model: 'model', + logprobs: true, + max_tokens: 0, + n: 0, + response_format: { + type: 'text', + json_schema: {}, + }, + stop: ['string'], + stream: false, + stream_options: { include_usage: true }, + temperature: 0, + tool_choice: { value: 'none' }, + tools: [ + { + function: { + name: 'name', + description: 'description', + parameters: { foo: 'bar' }, + }, + type: 'function', + }, + ], + top_p: 0, + }); }); }); diff --git a/tests/api-resources/completions.test.ts b/tests/api-resources/completions.test.ts index e21af584..bdc1f37b 100644 --- a/tests/api-resources/completions.test.ts +++ b/tests/api-resources/completions.test.ts @@ -2,11 +2,17 @@ import Writer from 'writer-sdk'; -const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); +const client = new Writer({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); describe('resource completions', () => { test('create: only required params', async () => { - const responsePromise = client.completions.create({ model: 'palmyra-x-003-instruct', prompt: 'Write me an SEO article about...' }); + const responsePromise = client.completions.create({ + model: 'palmyra-x-003-instruct', + prompt: 'Write me an SEO article about...', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -18,15 +24,15 @@ describe('resource completions', () => { test('create: required and optional params', async () => { const response = await client.completions.create({ - model: 'palmyra-x-003-instruct', - prompt: 'Write me an SEO article about...', - best_of: 1, - max_tokens: 150, - random_seed: 42, - stop: ['.'], - stream: false, - temperature: 0.7, - top_p: 0.9, - }); + model: 'palmyra-x-003-instruct', + prompt: 'Write me an SEO article about...', + best_of: 1, + max_tokens: 150, + random_seed: 42, + stop: ['.'], + stream: false, + temperature: 0.7, + top_p: 0.9, + }); }); }); diff --git a/tests/api-resources/files.test.ts b/tests/api-resources/files.test.ts index 159bffd6..895c0ee6 100644 --- a/tests/api-resources/files.test.ts +++ b/tests/api-resources/files.test.ts @@ -2,7 +2,10 @@ import Writer, { toFile } from 'writer-sdk'; -const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); +const client = new Writer({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); describe('resource files', () => { test('retrieve', async () => { @@ -29,17 +32,20 @@ describe('resource files', () => { test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.files.list({ - after: 'after', - before: 'before', - file_types: 'file_types', - graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - limit: 0, - order: 'asc', - status: 'in_progress', - }, { path: '/_stainless_unknown_path' })) - .rejects - .toThrow(Writer.NotFoundError); + await expect( + client.files.list( + { + after: 'after', + before: 'before', + file_types: 'file_types', + graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + limit: 0, + order: 'asc', + status: 'in_progress', + }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(Writer.NotFoundError); }); test('delete', async () => { @@ -70,7 +76,9 @@ describe('resource files', () => { // requests with binary data not yet supported in test environment test.skip('upload: only required params', async () => { - const responsePromise = client.files.upload({ content: await toFile(Buffer.from('Example data'), 'README.md'), 'Content-Disposition': 'Content-Disposition', + const responsePromise = client.files.upload({ + content: await toFile(Buffer.from('Example data'), 'README.md'), + 'Content-Disposition': 'Content-Disposition', 'Content-Type': 'Content-Type', }); const rawResponse = await responsePromise.asResponse(); @@ -85,10 +93,10 @@ describe('resource files', () => { // requests with binary data not yet supported in test environment test.skip('upload: required and optional params', async () => { const response = await client.files.upload({ - content: await toFile(Buffer.from('Example data'), 'README.md'), - 'Content-Disposition': 'Content-Disposition', + content: await toFile(Buffer.from('Example data'), 'README.md'), + 'Content-Disposition': 'Content-Disposition', 'Content-Type': 'Content-Type', - graphId: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - }); + graphId: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + }); }); }); diff --git a/tests/api-resources/graphs.test.ts b/tests/api-resources/graphs.test.ts index eed9e70f..626f36b6 100644 --- a/tests/api-resources/graphs.test.ts +++ b/tests/api-resources/graphs.test.ts @@ -2,7 +2,10 @@ import Writer from 'writer-sdk'; -const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); +const client = new Writer({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); describe('resource graphs', () => { test('create', async () => { @@ -51,14 +54,17 @@ describe('resource graphs', () => { test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.graphs.list({ - after: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - before: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', - limit: 0, - order: 'asc', - }, { path: '/_stainless_unknown_path' })) - .rejects - .toThrow(Writer.NotFoundError); + await expect( + client.graphs.list( + { + after: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + before: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + limit: 0, + order: 'asc', + }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(Writer.NotFoundError); }); test('delete', async () => { @@ -73,7 +79,9 @@ describe('resource graphs', () => { }); test('addFileToGraph: only required params', async () => { - const responsePromise = client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { file_id: 'file_id' }); + const responsePromise = client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { + file_id: 'file_id', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -84,11 +92,16 @@ describe('resource graphs', () => { }); test('addFileToGraph: required and optional params', async () => { - const response = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { file_id: 'file_id' }); + const response = await client.graphs.addFileToGraph('182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', { + file_id: 'file_id', + }); }); test('question: only required params', async () => { - const responsePromise = client.graphs.question({ graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], question: 'question' }); + const responsePromise = client.graphs.question({ + graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], + question: 'question', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -100,25 +113,27 @@ describe('resource graphs', () => { test('question: required and optional params', async () => { const response = await client.graphs.question({ - graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], - question: 'question', - query_config: { - grounding_level: 0, - inline_citations: true, - keyword_threshold: 0, - max_snippets: 1, - max_subquestions: 1, - max_tokens: 100, - search_weight: 0, - semantic_threshold: 0, - }, - stream: false, - subqueries: true, - }); + graph_ids: ['182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e'], + question: 'question', + query_config: { + grounding_level: 0, + inline_citations: true, + keyword_threshold: 0, + max_snippets: 1, + max_subquestions: 1, + max_tokens: 100, + search_weight: 0, + semantic_threshold: 0, + }, + stream: false, + subqueries: true, + }); }); test('removeFileFromGraph: only required params', async () => { - const responsePromise = client.graphs.removeFileFromGraph('file_id', { graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e' }); + const responsePromise = client.graphs.removeFileFromGraph('file_id', { + graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -129,6 +144,8 @@ describe('resource graphs', () => { }); test('removeFileFromGraph: required and optional params', async () => { - const response = await client.graphs.removeFileFromGraph('file_id', { graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e' }); + const response = await client.graphs.removeFileFromGraph('file_id', { + graph_id: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + }); }); }); diff --git a/tests/api-resources/models.test.ts b/tests/api-resources/models.test.ts index f9a688b5..ffe9b11d 100644 --- a/tests/api-resources/models.test.ts +++ b/tests/api-resources/models.test.ts @@ -2,7 +2,10 @@ import Writer from 'writer-sdk'; -const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); +const client = new Writer({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); describe('resource models', () => { test('list', async () => { diff --git a/tests/api-resources/tools.test.ts b/tests/api-resources/tools.test.ts index c35e964a..78f89f5a 100644 --- a/tests/api-resources/tools.test.ts +++ b/tests/api-resources/tools.test.ts @@ -2,7 +2,10 @@ import Writer from 'writer-sdk'; -const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); +const client = new Writer({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); describe('resource tools', () => { test('parsePdf: only required params', async () => { diff --git a/tests/api-resources/translation.test.ts b/tests/api-resources/translation.test.ts index 22d62eb4..9098b182 100644 --- a/tests/api-resources/translation.test.ts +++ b/tests/api-resources/translation.test.ts @@ -2,19 +2,22 @@ import Writer from 'writer-sdk'; -const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); +const client = new Writer({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); describe('resource translation', () => { test('translate: only required params', async () => { const responsePromise = client.translation.translate({ - formality: true, - length_control: true, - mask_profanity: true, - model: 'palmyra-translate', - source_language_code: 'en', - target_language_code: 'es', - text: 'Hello, world!', - }); + formality: true, + length_control: true, + mask_profanity: true, + model: 'palmyra-translate', + source_language_code: 'en', + target_language_code: 'es', + text: 'Hello, world!', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -26,13 +29,13 @@ describe('resource translation', () => { test('translate: required and optional params', async () => { const response = await client.translation.translate({ - formality: true, - length_control: true, - mask_profanity: true, - model: 'palmyra-translate', - source_language_code: 'en', - target_language_code: 'es', - text: 'Hello, world!', - }); + formality: true, + length_control: true, + mask_profanity: true, + model: 'palmyra-translate', + source_language_code: 'en', + target_language_code: 'es', + text: 'Hello, world!', + }); }); }); diff --git a/tests/api-resources/vision.test.ts b/tests/api-resources/vision.test.ts index 0b7ee56c..72b2795d 100644 --- a/tests/api-resources/vision.test.ts +++ b/tests/api-resources/vision.test.ts @@ -2,15 +2,21 @@ import Writer from 'writer-sdk'; -const client = new Writer({ apiKey: 'My API Key', baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010' }); +const client = new Writer({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); describe('resource vision', () => { test('analyze: only required params', async () => { const responsePromise = client.vision.analyze({ - model: 'palmyra-vision', - prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.', - variables: [{ file_id: 'f1234', name: 'image_1' }, { file_id: 'f9876', name: 'image_2' }], - }); + model: 'palmyra-vision', + prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.', + variables: [ + { file_id: 'f1234', name: 'image_1' }, + { file_id: 'f9876', name: 'image_2' }, + ], + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -22,9 +28,12 @@ describe('resource vision', () => { test('analyze: required and optional params', async () => { const response = await client.vision.analyze({ - model: 'palmyra-vision', - prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.', - variables: [{ file_id: 'f1234', name: 'image_1' }, { file_id: 'f9876', name: 'image_2' }], - }); + model: 'palmyra-vision', + prompt: 'Describe the difference between the image {{image_1}} and the image {{image_2}}.', + variables: [ + { file_id: 'f1234', name: 'image_1' }, + { file_id: 'f9876', name: 'image_2' }, + ], + }); }); }); diff --git a/tests/index.test.ts b/tests/index.test.ts index e6060dec..ab852e55 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -21,10 +21,10 @@ describe('instantiate client', () => { describe('defaultHeaders', () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - defaultHeaders: { 'X-My-Default-Header': '2' }, - apiKey: 'My API Key', -}) + baseURL: 'http://localhost:5000/', + defaultHeaders: { 'X-My-Default-Header': '2' }, + apiKey: 'My API Key', + }); test('they are used in the request', async () => { const { req } = await client.buildRequest({ path: '/foo', method: 'post' }); @@ -49,191 +49,193 @@ describe('instantiate client', () => { expect(req.headers.has('x-my-default-header')).toBe(false); }); }); -describe('logging', () => { - const env = process.env; + describe('logging', () => { + const env = process.env; - beforeEach(() => { - process.env = { ...env }; - process.env['WRITER_LOG'] = undefined; - }); + beforeEach(() => { + process.env = { ...env }; + process.env['WRITER_LOG'] = undefined; + }); - afterEach(() => { - process.env = env; - }); + afterEach(() => { + process.env = env; + }); - const forceAPIResponseForClient = async (client: Writer) => { - await new APIPromise( - client, - Promise.resolve({ - response: new Response(), - controller: new AbortController(), - requestLogID: 'log_000000', - retryOfRequestLogID: undefined, - startTime: Date.now(), - options: { - method: 'get', - path: '/', - }, - }), - ); - }; - - test('debug logs when log level is debug', async () => { - const debugMock = jest.fn(); - const logger = { - debug: debugMock, - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), + const forceAPIResponseForClient = async (client: Writer) => { + await new APIPromise( + client, + Promise.resolve({ + response: new Response(), + controller: new AbortController(), + requestLogID: 'log_000000', + retryOfRequestLogID: undefined, + startTime: Date.now(), + options: { + method: 'get', + path: '/', + }, + }), + ); }; - const client = new Writer({ - logger: logger, - logLevel: 'debug', - apiKey: 'My API Key', -}); + test('debug logs when log level is debug', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; - await forceAPIResponseForClient(client); - expect(debugMock).toHaveBeenCalled(); - }); + const client = new Writer({ + logger: logger, + logLevel: 'debug', + apiKey: 'My API Key', + }); - test('default logLevel is warn', async () => { - const client = new Writer({ apiKey: 'My API Key' }); - expect(client.logLevel).toBe('warn'); - }); + await forceAPIResponseForClient(client); + expect(debugMock).toHaveBeenCalled(); + }); - test('debug logs are skipped when log level is info', async () => { - const debugMock = jest.fn(); - const logger = { - debug: debugMock, - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; + test('default logLevel is warn', async () => { + const client = new Writer({ apiKey: 'My API Key' }); + expect(client.logLevel).toBe('warn'); + }); - const client = new Writer({ - logger: logger, - logLevel: 'info', - apiKey: 'My API Key', -}); + test('debug logs are skipped when log level is info', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; - await forceAPIResponseForClient(client); - expect(debugMock).not.toHaveBeenCalled(); - }); + const client = new Writer({ + logger: logger, + logLevel: 'info', + apiKey: 'My API Key', + }); - test('debug logs happen with debug env var', async () => { - const debugMock = jest.fn(); - const logger = { - debug: debugMock, - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; + await forceAPIResponseForClient(client); + expect(debugMock).not.toHaveBeenCalled(); + }); - process.env['WRITER_LOG'] = 'debug'; - const client = new Writer({ logger: logger, apiKey: 'My API Key' }); - expect(client.logLevel).toBe('debug'); + test('debug logs happen with debug env var', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; - await forceAPIResponseForClient(client); - expect(debugMock).toHaveBeenCalled(); - }); + process.env['WRITER_LOG'] = 'debug'; + const client = new Writer({ logger: logger, apiKey: 'My API Key' }); + expect(client.logLevel).toBe('debug'); - test('warn when env var level is invalid', async () => { - const warnMock = jest.fn(); - const logger = { - debug: jest.fn(), - info: jest.fn(), - warn: warnMock, - error: jest.fn(), - }; + await forceAPIResponseForClient(client); + expect(debugMock).toHaveBeenCalled(); + }); - process.env['WRITER_LOG'] = 'not a log level'; - const client = new Writer({ logger: logger, apiKey: 'My API Key' }); - expect(client.logLevel).toBe('warn'); - expect(warnMock).toHaveBeenCalledWith('process.env[\'WRITER_LOG\'] was set to "not a log level", expected one of ["off","error","warn","info","debug"]'); - }); + test('warn when env var level is invalid', async () => { + const warnMock = jest.fn(); + const logger = { + debug: jest.fn(), + info: jest.fn(), + warn: warnMock, + error: jest.fn(), + }; - test('client log level overrides env var', async () => { - const debugMock = jest.fn(); - const logger = { - debug: debugMock, - info: jest.fn(), - warn: jest.fn(), - error: jest.fn(), - }; + process.env['WRITER_LOG'] = 'not a log level'; + const client = new Writer({ logger: logger, apiKey: 'My API Key' }); + expect(client.logLevel).toBe('warn'); + expect(warnMock).toHaveBeenCalledWith( + 'process.env[\'WRITER_LOG\'] was set to "not a log level", expected one of ["off","error","warn","info","debug"]', + ); + }); - process.env['WRITER_LOG'] = 'debug'; - const client = new Writer({ - logger: logger, - logLevel: 'off', - apiKey: 'My API Key', -}); + test('client log level overrides env var', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; - await forceAPIResponseForClient(client); - expect(debugMock).not.toHaveBeenCalled(); - }); + process.env['WRITER_LOG'] = 'debug'; + const client = new Writer({ + logger: logger, + logLevel: 'off', + apiKey: 'My API Key', + }); - test('no warning logged for invalid env var level + valid client level', async () => { - const warnMock = jest.fn(); - const logger = { - debug: jest.fn(), - info: jest.fn(), - warn: warnMock, - error: jest.fn(), - }; + await forceAPIResponseForClient(client); + expect(debugMock).not.toHaveBeenCalled(); + }); - process.env['WRITER_LOG'] = 'not a log level'; - const client = new Writer({ - logger: logger, - logLevel: 'debug', - apiKey: 'My API Key', -}); - expect(client.logLevel).toBe('debug'); - expect(warnMock).not.toHaveBeenCalled(); + test('no warning logged for invalid env var level + valid client level', async () => { + const warnMock = jest.fn(); + const logger = { + debug: jest.fn(), + info: jest.fn(), + warn: warnMock, + error: jest.fn(), + }; + + process.env['WRITER_LOG'] = 'not a log level'; + const client = new Writer({ + logger: logger, + logLevel: 'debug', + apiKey: 'My API Key', + }); + expect(client.logLevel).toBe('debug'); + expect(warnMock).not.toHaveBeenCalled(); + }); }); -}); describe('defaultQuery', () => { test('with null query params given', () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - defaultQuery: { apiVersion: 'foo' }, - apiKey: 'My API Key', -}); + baseURL: 'http://localhost:5000/', + defaultQuery: { apiVersion: 'foo' }, + apiKey: 'My API Key', + }); expect(client.buildURL('/foo', null)).toEqual('http://localhost:5000/foo?apiVersion=foo'); }); test('multiple default query params', () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - defaultQuery: { apiVersion: 'foo', hello: 'world' }, - apiKey: 'My API Key', -}); + baseURL: 'http://localhost:5000/', + defaultQuery: { apiVersion: 'foo', hello: 'world' }, + apiKey: 'My API Key', + }); expect(client.buildURL('/foo', null)).toEqual('http://localhost:5000/foo?apiVersion=foo&hello=world'); }); test('overriding with `undefined`', () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - defaultQuery: { hello: 'world' }, - apiKey: 'My API Key', -}) + baseURL: 'http://localhost:5000/', + defaultQuery: { hello: 'world' }, + apiKey: 'My API Key', + }); expect(client.buildURL('/foo', { hello: undefined })).toEqual('http://localhost:5000/foo'); }); }); test('custom fetch', async () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - apiKey: 'My API Key', - fetch: (url) => { - return Promise.resolve( - new Response(JSON.stringify({ url, custom: true }), { - headers: { 'Content-Type': 'application/json' }, - }), - ); -}, -}); + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + fetch: (url) => { + return Promise.resolve( + new Response(JSON.stringify({ url, custom: true }), { + headers: { 'Content-Type': 'application/json' }, + }), + ); + }, + }); const response = await client.get('/foo'); expect(response).toEqual({ url: 'http://localhost:5000/foo', custom: true }); @@ -242,37 +244,35 @@ describe('logging', () => { test('explicit global fetch', async () => { // make sure the global fetch type is assignable to our Fetch type const client = new Writer({ - baseURL: 'http://localhost:5000/', - apiKey: 'My API Key', - fetch: defaultFetch, -}); + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + fetch: defaultFetch, + }); }); test('custom signal', async () => { const client = new Writer({ - baseURL: process.env["TEST_API_BASE_URL"] ?? 'http://127.0.0.1:4010', - apiKey: 'My API Key', - fetch: (...args) => { - return new Promise((resolve, reject) => - setTimeout( - () => - defaultFetch(...args) - .then(resolve) - .catch(reject), - 300, - ), - ); -}, -}); + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + apiKey: 'My API Key', + fetch: (...args) => { + return new Promise((resolve, reject) => + setTimeout( + () => + defaultFetch(...args) + .then(resolve) + .catch(reject), + 300, + ), + ); + }, + }); const controller = new AbortController(); setTimeout(() => controller.abort(), 200); const spy = jest.spyOn(client, 'request'); - await expect(client.get('/foo', { signal: controller.signal })).rejects.toThrowError( - APIUserAbortError, - ); + await expect(client.get('/foo', { signal: controller.signal })).rejects.toThrowError(APIUserAbortError); expect(spy).toHaveBeenCalledTimes(1); }); @@ -284,10 +284,10 @@ describe('logging', () => { }; const client = new Writer({ - baseURL: 'http://localhost:5000/', - apiKey: 'My API Key', - fetch: testFetch, -}); + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + fetch: testFetch, + }); await client.patch('/foo'); expect(capturedRequest?.method).toEqual('PATCH'); @@ -322,29 +322,35 @@ describe('logging', () => { test('empty env variable', () => { process.env['WRITER_BASE_URL'] = ''; // empty const client = new Writer({ apiKey: 'My API Key' }); - expect(client.baseURL).toEqual('https://api.writer.com') + expect(client.baseURL).toEqual('https://api.writer.com'); }); test('blank env variable', () => { process.env['WRITER_BASE_URL'] = ' '; // blank const client = new Writer({ apiKey: 'My API Key' }); - expect(client.baseURL).toEqual('https://api.writer.com') + expect(client.baseURL).toEqual('https://api.writer.com'); }); test('in request options', () => { const client = new Writer({ apiKey: 'My API Key' }); - expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual('http://localhost:5000/option/foo'); + expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual( + 'http://localhost:5000/option/foo', + ); }); test('in request options overridden by client options', () => { const client = new Writer({ apiKey: 'My API Key', baseURL: 'http://localhost:5000/client' }); - expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual('http://localhost:5000/client/foo'); + expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual( + 'http://localhost:5000/client/foo', + ); }); test('in request options overridden by env variable', () => { process.env['WRITER_BASE_URL'] = 'http://localhost:5000/env'; const client = new Writer({ apiKey: 'My API Key' }); - expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual('http://localhost:5000/env/foo'); + expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual( + 'http://localhost:5000/env/foo', + ); }); }); @@ -360,10 +366,10 @@ describe('logging', () => { describe('withOptions', () => { test('creates a new client with overridden options', async () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - maxRetries: 3, - apiKey: 'My API Key', - }); + baseURL: 'http://localhost:5000/', + maxRetries: 3, + apiKey: 'My API Key', + }); const newClient = client.withOptions({ maxRetries: 5, @@ -385,11 +391,11 @@ describe('logging', () => { test('inherits options from the parent client', async () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - defaultHeaders: { 'X-Test-Header': 'test-value' }, - defaultQuery: { 'test-param': 'test-value' }, - apiKey: 'My API Key', - }); + baseURL: 'http://localhost:5000/', + defaultHeaders: { 'X-Test-Header': 'test-value' }, + defaultQuery: { 'test-param': 'test-value' }, + apiKey: 'My API Key', + }); const newClient = client.withOptions({ baseURL: 'http://localhost:5001/', @@ -404,10 +410,10 @@ describe('logging', () => { test('respects runtime property changes when creating new client', () => { const client = new Writer({ - baseURL: 'http://localhost:5000/', - timeout: 1000, - apiKey: 'My API Key', - }); + baseURL: 'http://localhost:5000/', + timeout: 1000, + apiKey: 'My API Key', + }); // Modify the client properties directly after creation client.baseURL = 'http://localhost:6000/'; @@ -453,13 +459,18 @@ describe('request building', () => { describe('custom headers', () => { test('handles undefined', async () => { - const { req } = await client.buildRequest({ path: '/foo', method: 'post', body: { value: 'hello' }, headers: { 'X-Foo': 'baz', 'x-foo': 'bar', 'x-Foo': undefined, 'x-baz': 'bam', 'X-Baz': null } }); + const { req } = await client.buildRequest({ + path: '/foo', + method: 'post', + body: { value: 'hello' }, + headers: { 'X-Foo': 'baz', 'x-foo': 'bar', 'x-Foo': undefined, 'x-baz': 'bam', 'X-Baz': null }, + }); expect(req.headers.get('x-foo')).toEqual('bar'); expect(req.headers.get('x-Foo')).toEqual('bar'); expect(req.headers.get('X-Foo')).toEqual('bar'); expect(req.headers.get('x-baz')).toEqual(null); }); - }) + }); }); describe('default encoder', () => { @@ -536,37 +547,40 @@ describe('default encoder', () => { describe('retries', () => { test('retry on timeout', async () => { let count = 0; - const testFetch = async (url: string | URL | Request, { signal }: RequestInit = {}): Promise => { - if (count++ === 0) { - return new Promise((resolve, reject) => - signal?.addEventListener('abort', () => reject(new Error('timed out'))), - ); - } - return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); - }; - - const client = new Writer({ - apiKey: 'My API Key', - timeout: 10, - fetch: testFetch, - }); + const testFetch = async ( + url: string | URL | Request, + { signal }: RequestInit = {}, + ): Promise => { + if (count++ === 0) { + return new Promise( + (resolve, reject) => signal?.addEventListener('abort', () => reject(new Error('timed out'))), + ); + } + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; - expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); - expect(count).toEqual(2); - expect( - await client - .request({ path: '/foo', method: 'get' }) - .asResponse() - .then((r) => r.text()), - ).toEqual(JSON.stringify({ a: 1 })); - expect(count).toEqual(3); + const client = new Writer({ + apiKey: 'My API Key', + timeout: 10, + fetch: testFetch, }); + expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); + expect(count).toEqual(2); + expect( + await client + .request({ path: '/foo', method: 'get' }) + .asResponse() + .then((r) => r.text()), + ).toEqual(JSON.stringify({ a: 1 })); + expect(count).toEqual(3); + }); + test('retry count header', async () => { let count = 0; let capturedRequest: RequestInit | undefined; const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { - count++ + count++; if (count <= 2) { return new Response(undefined, { status: 429, @@ -580,10 +594,10 @@ describe('retries', () => { }; const client = new Writer({ - apiKey: 'My API Key', - fetch: testFetch, - maxRetries: 4, - }); + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + }); expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); @@ -595,7 +609,7 @@ describe('retries', () => { let count = 0; let capturedRequest: RequestInit | undefined; const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { - count++ + count++; if (count <= 2) { return new Response(undefined, { status: 429, @@ -608,10 +622,10 @@ describe('retries', () => { return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; const client = new Writer({ - apiKey: 'My API Key', - fetch: testFetch, - maxRetries: 4, - }); + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + }); expect( await client.request({ @@ -628,7 +642,7 @@ describe('retries', () => { let count = 0; let capturedRequest: RequestInit | undefined; const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { - count++ + count++; if (count <= 2) { return new Response(undefined, { status: 429, @@ -641,11 +655,11 @@ describe('retries', () => { return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; const client = new Writer({ - apiKey: 'My API Key', - fetch: testFetch, - maxRetries: 4, - defaultHeaders: { 'X-Stainless-Retry-Count': null }, - }); + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + defaultHeaders: { 'X-Stainless-Retry-Count': null }, + }); expect( await client.request({ @@ -661,7 +675,7 @@ describe('retries', () => { let count = 0; let capturedRequest: RequestInit | undefined; const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { - count++ + count++; if (count <= 2) { return new Response(undefined, { status: 429, @@ -674,10 +688,10 @@ describe('retries', () => { return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; const client = new Writer({ - apiKey: 'My API Key', - fetch: testFetch, - maxRetries: 4, - }); + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + }); expect( await client.request({ @@ -692,7 +706,10 @@ describe('retries', () => { test('retry on 429 with retry-after', async () => { let count = 0; - const testFetch = async (url: string | URL | Request, { signal }: RequestInit = {}): Promise => { + const testFetch = async ( + url: string | URL | Request, + { signal }: RequestInit = {}, + ): Promise => { if (count++ === 0) { return new Response(undefined, { status: 429, @@ -719,7 +736,10 @@ describe('retries', () => { test('retry on 429 with retry-after-ms', async () => { let count = 0; - const testFetch = async (url: string | URL | Request, { signal }: RequestInit = {}): Promise => { + const testFetch = async ( + url: string | URL | Request, + { signal }: RequestInit = {}, + ): Promise => { if (count++ === 0) { return new Response(undefined, { status: 429, diff --git a/tests/streaming.test.ts b/tests/streaming.test.ts index 2915814b..34d28755 100644 --- a/tests/streaming.test.ts +++ b/tests/streaming.test.ts @@ -242,4 +242,4 @@ test('error handling', async () => { `[Error: {"type":"error","error":{"type":"overloaded_error","message":"Overloaded"}}]`, ); await err.toBeInstanceOf(APIError); -});; +}); diff --git a/tests/stringifyQuery.test.ts b/tests/stringifyQuery.test.ts index 75691ca8..90cf3c26 100644 --- a/tests/stringifyQuery.test.ts +++ b/tests/stringifyQuery.test.ts @@ -2,24 +2,26 @@ import { stringifyQuery } from 'writer-sdk/internal/utils/query'; -describe(stringifyQuery, () => { for (const [input, expected] of [ - [{ a: '1', b: 2, c: true }, 'a=1&b=2&c=true'], - [{ a: null, b: false, c: undefined }, 'a=&b=false'], - [{ 'a/b': 1.28341 }, `${encodeURIComponent('a/b')}=1.28341`], - [ - { 'a/b': 'c/d', 'e=f': 'g&h' }, - `${encodeURIComponent('a/b')}=${encodeURIComponent('c/d')}&${encodeURIComponent( - 'e=f', - )}=${encodeURIComponent('g&h')}`, - ], -] as const) { - it(`${JSON.stringify(input)} -> ${expected}`, () => { - expect(stringifyQuery(input)).toEqual(expected); - }); -} +describe(stringifyQuery, () => { + for (const [input, expected] of [ + [{ a: '1', b: 2, c: true }, 'a=1&b=2&c=true'], + [{ a: null, b: false, c: undefined }, 'a=&b=false'], + [{ 'a/b': 1.28341 }, `${encodeURIComponent('a/b')}=1.28341`], + [ + { 'a/b': 'c/d', 'e=f': 'g&h' }, + `${encodeURIComponent('a/b')}=${encodeURIComponent('c/d')}&${encodeURIComponent( + 'e=f', + )}=${encodeURIComponent('g&h')}`, + ], + ] as const) { + it(`${JSON.stringify(input)} -> ${expected}`, () => { + expect(stringifyQuery(input)).toEqual(expected); + }); + } -for (const value of [[], {}, new Date()]) { - it(`${JSON.stringify(value)} -> `, () => { - expect(() => stringifyQuery({ value })).toThrow(`Cannot stringify type ${typeof value}`); - }); -} }) + for (const value of [[], {}, new Date()]) { + it(`${JSON.stringify(value)} -> `, () => { + expect(() => stringifyQuery({ value })).toThrow(`Cannot stringify type ${typeof value}`); + }); + } +}); diff --git a/yarn.lock b/yarn.lock index 80ed97d0..ba2b2605 100644 --- a/yarn.lock +++ b/yarn.lock @@ -709,6 +709,11 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@pkgr/core@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c" + integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw== + "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -1510,6 +1515,14 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +eslint-plugin-prettier@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.1.tgz#99b55d7dd70047886b2222fdd853665f180b36af" + integrity sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg== + dependencies: + prettier-linter-helpers "^1.0.0" + synckit "^0.11.7" + eslint-plugin-unused-imports@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz#62ddc7446ccbf9aa7b6f1f0b00a980423cda2738" @@ -1668,6 +1681,11 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-diff@^1.1.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" @@ -2834,6 +2852,14 @@ prelude-ls@^1.2.1: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== + +prettier-linter-helpers@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz#6a31f88a4bad6c7adda253de12ba4edaea80ebcd" + integrity sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg== + dependencies: + fast-diff "^1.1.2" + prettier@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.1.tgz#6ba9f23165d690b6cbdaa88cb0807278f7019848" @@ -3135,6 +3161,13 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +synckit@^0.11.7: + version "0.11.8" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.8.tgz#b2aaae998a4ef47ded60773ad06e7cb821f55457" + integrity sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A== + dependencies: + "@pkgr/core" "^0.2.4" + test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -3278,10 +3311,10 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -undici-types@~6.21.0: - version "6.21.0" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" - integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== unicode-emoji-modifier-base@^1.0.0: version "1.0.0" From 775860c7b034ec2b29133441ca42ff1653559737 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 27 Apr 2026 22:35:29 +0000 Subject: [PATCH 07/22] feat: support setting headers via env --- src/client.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/client.ts b/src/client.ts index d43b78e2..eb4689c9 100644 --- a/src/client.ts +++ b/src/client.ts @@ -252,6 +252,18 @@ export class Writer { this.fetch = options.fetch ?? Shims.getDefaultFetch(); this.#encoder = Opts.FallbackEncoder; + const customHeadersEnv = readEnv('WRITER_CUSTOM_HEADERS'); + if (customHeadersEnv) { + const parsed: Record = {}; + for (const line of customHeadersEnv.split('\n')) { + const colon = line.indexOf(':'); + if (colon >= 0) { + parsed[line.substring(0, colon).trim()] = line.substring(colon + 1).trim(); + } + } + options.defaultHeaders = { ...parsed, ...options.defaultHeaders }; + } + this._options = options; this.apiKey = apiKey; From be7d4a0d88334afce883d534ca85d735aa026bc4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 17:54:39 +0000 Subject: [PATCH 08/22] chore(format): run eslint and prettier separately --- .github/workflows/release-doctor.yml | 1 - README.md | 14 ++++++------ bin/cli | 14 ++++++++---- eslint.config.mjs | 3 --- package.json | 1 - packages/mcp-server/manifest.json | 8 ++----- packages/mcp-server/yarn.lock | 9 ++++++++ scripts/fast-format | 9 +++----- scripts/format | 3 +-- scripts/lint | 3 +++ src/internal/types.ts | 14 ++++++------ yarn.lock | 32 ---------------------------- 12 files changed, 41 insertions(+), 70 deletions(-) diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 897f1dab..db18c6eb 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -19,4 +19,3 @@ jobs: bash ./bin/check-release-environment env: NPM_TOKEN: ${{ secrets.WRITER_NPM_TOKEN || secrets.NPM_TOKEN }} - diff --git a/README.md b/README.md index a4d28040..c642d075 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ const client = new Writer({ ``` > Never hard-code your API keys in source code or commit them to version control systems like GitHub. -> We recommend adding `WRITER_API_KEY="My API Key"` to your `.env` file so that your API Key is not stored in source control. +> We recommend adding `WRITER_API_KEY="My API Key"` to your `.env` file so that your API Key is not stored in source control. ## Usage @@ -125,13 +125,13 @@ const stream = await client.chat.chat({ model: 'palmyra-x5', stream: true, }); -let outputText = ""; +let outputText = ''; for await (const chunk of stream) { - if (chunk.choices[0]?.delta?.content) { - outputText += chunk.choices[0].delta.content; - } else { - continue; - } + if (chunk.choices[0]?.delta?.content) { + outputText += chunk.choices[0].delta.content; + } else { + continue; + } } console.log(outputText); ``` diff --git a/bin/cli b/bin/cli index 87d8f71a..69403d48 100755 --- a/bin/cli +++ b/bin/cli @@ -8,15 +8,21 @@ const commands = { fn: () => { const result = spawnSync( 'npx', - ['-y', 'https://github.com/stainless-api/migrate-ts/releases/download/0.0.2/stainless-api-migrate-0.0.2-6.tgz', '--migrationConfig', require.resolve('./migration-config.json'), ...process.argv.slice(3)], + [ + '-y', + 'https://github.com/stainless-api/migrate-ts/releases/download/0.0.2/stainless-api-migrate-0.0.2-6.tgz', + '--migrationConfig', + require.resolve('./migration-config.json'), + ...process.argv.slice(3), + ], { stdio: 'inherit' }, ); if (result.status !== 0) { process.exit(result.status); } - } - } -} + }, + }, +}; function exitWithHelp() { console.log(`Usage: writer-sdk `); diff --git a/eslint.config.mjs b/eslint.config.mjs index 3954b642..edd23b90 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,7 +1,6 @@ // @ts-check import tseslint from 'typescript-eslint'; import unusedImports from 'eslint-plugin-unused-imports'; -import prettier from 'eslint-plugin-prettier'; export default tseslint.config( { @@ -14,11 +13,9 @@ export default tseslint.config( plugins: { '@typescript-eslint': tseslint.plugin, 'unused-imports': unusedImports, - prettier, }, rules: { 'no-unused-vars': 'off', - 'prettier/prettier': 'error', 'unused-imports/no-unused-imports': 'error', 'no-restricted-imports': [ 'error', diff --git a/package.json b/package.json index b824c951..8419e108 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,6 @@ "@typescript-eslint/eslint-plugin": "8.31.1", "@typescript-eslint/parser": "8.31.1", "eslint": "^9.39.1", - "eslint-plugin-prettier": "^5.4.1", "eslint-plugin-unused-imports": "^4.1.4", "fast-check": "^3.23.1", "iconv-lite": "^0.6.3", diff --git a/packages/mcp-server/manifest.json b/packages/mcp-server/manifest.json index 423d6234..238f5bdf 100644 --- a/packages/mcp-server/manifest.json +++ b/packages/mcp-server/manifest.json @@ -18,9 +18,7 @@ "entry_point": "index.js", "mcp_config": { "command": "node", - "args": [ - "${__dirname}/index.js" - ], + "args": ["${__dirname}/index.js"], "env": { "WRITER_API_KEY": "${user_config.WRITER_API_KEY}" } @@ -41,7 +39,5 @@ "node": ">=18.0.0" } }, - "keywords": [ - "api" - ] + "keywords": ["api"] } diff --git a/packages/mcp-server/yarn.lock b/packages/mcp-server/yarn.lock index c7e37692..f5c309e2 100644 --- a/packages/mcp-server/yarn.lock +++ b/packages/mcp-server/yarn.lock @@ -3085,6 +3085,11 @@ minimist@^1.2.5, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== +minisearch@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/minisearch/-/minisearch-7.2.0.tgz#3dc30e41e9464b3836553b6d969b656614f8f359" + integrity sha512-dqT2XBYUOZOiC5t2HRnwADjhNS2cecp9u+TJRiJ1Qp/f5qjkeT5APcGPjHw+bz89Ms8Jp+cG4AlE+QZ/QnDglg== + mkdirp@^2.1.6: version "2.1.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" @@ -4105,6 +4110,10 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" +"writer-sdk@link:../../dist": + version "0.0.0" + uid "" + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" diff --git a/scripts/fast-format b/scripts/fast-format index 53721ac0..0cd6b02d 100755 --- a/scripts/fast-format +++ b/scripts/fast-format @@ -31,10 +31,7 @@ if ! [ -z "$ESLINT_FILES" ]; then fi echo "==> Running prettier --write" -# format things eslint didn't -PRETTIER_FILES="$(grep '\.\(js\|json\)$' "$FILE_LIST" || true)" -if ! [ -z "$PRETTIER_FILES" ]; then - echo "$PRETTIER_FILES" | xargs ./node_modules/.bin/prettier \ - --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern \ - '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' +if ! [ -z "$FILE_LIST" ]; then + cat "$FILE_LIST" | xargs ./node_modules/prettier/bin/prettier.cjs \ + --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern --ignore-unknown fi diff --git a/scripts/format b/scripts/format index 7a756401..e14103f9 100755 --- a/scripts/format +++ b/scripts/format @@ -8,5 +8,4 @@ echo "==> Running eslint --fix" ./node_modules/.bin/eslint --fix . echo "==> Running prettier --write" -# format things eslint didn't -./node_modules/.bin/prettier --write --cache --cache-strategy metadata . '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' +./node_modules/prettier/bin/prettier.cjs --write --cache --cache-strategy metadata . diff --git a/scripts/lint b/scripts/lint index 3ffb78a6..45aeb536 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,6 +4,9 @@ set -e cd "$(dirname "$0")/.." +echo "==> Running prettier --check" +./node_modules/prettier/bin/prettier.cjs --check . + echo "==> Running eslint" ./node_modules/.bin/eslint . diff --git a/src/internal/types.ts b/src/internal/types.ts index b668dfc0..a050513a 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -40,7 +40,6 @@ type OverloadedParameters = : T extends (...args: infer A) => unknown ? A : never; -/* eslint-disable */ /** * These imports attempt to get types from a parent package's dependencies. * Unresolved bare specifiers can trigger [automatic type acquisition][1] in some projects, which @@ -63,19 +62,18 @@ type OverloadedParameters = * * [1]: https://www.typescriptlang.org/tsconfig/#typeAcquisition */ -/** @ts-ignore For users with \@types/node */ +/** @ts-ignore For users with \@types/node */ /* prettier-ignore */ type UndiciTypesRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with undici */ +/** @ts-ignore For users with undici */ /* prettier-ignore */ type UndiciRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with \@types/bun */ +/** @ts-ignore For users with \@types/bun */ /* prettier-ignore */ type BunRequestInit = globalThis.FetchRequestInit; -/** @ts-ignore For users with node-fetch@2 */ +/** @ts-ignore For users with node-fetch@2 */ /* prettier-ignore */ type NodeFetch2RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ +/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ /* prettier-ignore */ type NodeFetch3RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users who use Deno */ +/** @ts-ignore For users who use Deno */ /* prettier-ignore */ type FetchRequestInit = NonNullable[1]>; -/* eslint-enable */ type RequestInits = | NotAny diff --git a/yarn.lock b/yarn.lock index ba2b2605..216bebc8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -709,11 +709,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@pkgr/core@^0.2.4": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c" - integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw== - "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -1515,14 +1510,6 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-plugin-prettier@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.1.tgz#99b55d7dd70047886b2222fdd853665f180b36af" - integrity sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg== - dependencies: - prettier-linter-helpers "^1.0.0" - synckit "^0.11.7" - eslint-plugin-unused-imports@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz#62ddc7446ccbf9aa7b6f1f0b00a980423cda2738" @@ -1681,11 +1668,6 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-diff@^1.1.2: - version "1.3.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" - integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== - fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" @@ -2853,13 +2835,6 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== -prettier-linter-helpers@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz#6a31f88a4bad6c7adda253de12ba4edaea80ebcd" - integrity sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg== - dependencies: - fast-diff "^1.1.2" - prettier@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.1.tgz#6ba9f23165d690b6cbdaa88cb0807278f7019848" @@ -3161,13 +3136,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -synckit@^0.11.7: - version "0.11.8" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.8.tgz#b2aaae998a4ef47ded60773ad06e7cb821f55457" - integrity sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A== - dependencies: - "@pkgr/core" "^0.2.4" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" From 6a457206747179f91a6bd085e19b26b68d5caf99 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 17:53:53 +0000 Subject: [PATCH 09/22] chore: avoid formatting file that gets changed during releases --- .prettierignore | 1 + packages/mcp-server/manifest.json | 8 ++++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.prettierignore b/.prettierignore index 7cc13dd1..36afd3b3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,6 +2,7 @@ CHANGELOG.md /ecosystem-tests/*/** /node_modules /deno +/packages/mcp-server/manifest.json # don't format tsc output, will break source maps dist diff --git a/packages/mcp-server/manifest.json b/packages/mcp-server/manifest.json index 238f5bdf..423d6234 100644 --- a/packages/mcp-server/manifest.json +++ b/packages/mcp-server/manifest.json @@ -18,7 +18,9 @@ "entry_point": "index.js", "mcp_config": { "command": "node", - "args": ["${__dirname}/index.js"], + "args": [ + "${__dirname}/index.js" + ], "env": { "WRITER_API_KEY": "${user_config.WRITER_API_KEY}" } @@ -39,5 +41,7 @@ "node": ">=18.0.0" } }, - "keywords": ["api"] + "keywords": [ + "api" + ] } From 5d5ce86c03a9fa92bdd611bd911f07fed973933c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:19:22 +0000 Subject: [PATCH 10/22] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 18b117f4..aaa8b768 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 30 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/writerai%2Fwriter-ea6b4de3976794a02ea8fc01669d901cd7b159ba0d598cc9653e01c987a2f806.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/writerai/writer-ea6b4de3976794a02ea8fc01669d901cd7b159ba0d598cc9653e01c987a2f806.yml openapi_spec_hash: 4d4a9ba232d19a6180e6d4a7d5566103 config_hash: 8701b1a467238f1afdeceeb7feb1adc6 From e834858870c77d78f88dae3bca85531c542aa311 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 30 Apr 2026 16:28:12 +0000 Subject: [PATCH 11/22] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index aaa8b768..45b858e1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 30 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/writerai/writer-ea6b4de3976794a02ea8fc01669d901cd7b159ba0d598cc9653e01c987a2f806.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/writerai/writer-275de8f7afa2d37404ebebc082dda35e70ab94437de270b5bc6e2fdc94c9fdae.yml openapi_spec_hash: 4d4a9ba232d19a6180e6d4a7d5566103 config_hash: 8701b1a467238f1afdeceeb7feb1adc6 From 34a1c2e84ada77d9b1d6aa3b94edcc9ebebc9244 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 20:45:39 +0000 Subject: [PATCH 12/22] docs: update http mcp docs --- packages/mcp-server/src/local-docs-search.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index f90a9750..7e66adaf 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -468,7 +468,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, http: { example: - 'curl https://api.writer.com/v1/completions \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "model": "palmyra-x-003-instruct",\n "prompt": "Write me an SEO article about..."\n }\'', + 'curl https://api.writer.com/v1/completions \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "model": "palmyra-x-003-instruct",\n "prompt": "Write me an SEO article about...",\n "best_of": 1,\n "max_tokens": 150,\n "random_seed": 42,\n "stop": [\n "."\n ],\n "stream": false,\n "temperature": 0.7,\n "top_p": 0.9\n }\'', }, }, }, @@ -1087,7 +1087,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ }, http: { example: - "curl https://api.writer.com/v1/tools/web-search \\\n -H 'Content-Type: application/json' \\\n -H \"Authorization: Bearer $WRITER_API_KEY\" \\\n -d '{}'", + 'curl https://api.writer.com/v1/tools/web-search \\\n -H \'Content-Type: application/json\' \\\n -H "Authorization: Bearer $WRITER_API_KEY" \\\n -d \'{\n "include_domains": [\n "dev.writer.com"\n ],\n "query": "How do I get an API key for the Writer API?"\n }\'', }, }, }, From 7b2b3a92068d07ca8d292adfe1059870cbe5265d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 May 2026 14:54:30 +0000 Subject: [PATCH 13/22] chore: redact api-key headers in debug logs --- src/internal/utils/log.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts index b6662952..e611b194 100644 --- a/src/internal/utils/log.ts +++ b/src/internal/utils/log.ts @@ -107,6 +107,8 @@ export const formatRequestDetails = (details: { name, ( name.toLowerCase() === 'authorization' || + name.toLowerCase() === 'api-key' || + name.toLowerCase() === 'x-api-key' || name.toLowerCase() === 'cookie' || name.toLowerCase() === 'set-cookie' ) ? From cbc04e6bd2b3cb3002f7ebb9ec0019c258ffbd53 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 12 May 2026 19:12:56 +0000 Subject: [PATCH 14/22] ci: pin GitHub Actions to commit SHAs Pin all GitHub Actions referenced in generated workflows (both first-party `actions/*` and third-party) to immutable commit SHAs. Updating pinned actions is now a deliberate codegen-side bump rather than implicit on every workflow run. --- .github/workflows/ci.yml | 14 +++++++------- .github/workflows/publish-npm.yml | 4 ++-- .github/workflows/release-doctor.yml | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af17f338..bbabce78 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,10 +21,10 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/writer-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '22' @@ -43,10 +43,10 @@ jobs: contents: read id-token: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '22' @@ -61,7 +61,7 @@ jobs: github.repository == 'stainless-sdks/writer-typescript' && !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc - uses: actions/github-script@v8 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: core.setOutput('github_token', await core.getIDToken()); @@ -91,10 +91,10 @@ jobs: runs-on: ${{ github.repository == 'stainless-sdks/writer-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '22' diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index e977e568..ed7e1cf5 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -20,10 +20,10 @@ jobs: contents: write steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v3 + uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1 with: node-version: '20' diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index db18c6eb..b09d8cd1 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -12,7 +12,7 @@ jobs: if: github.repository == 'writer/writer-node' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Check release environment run: | From c4c7f9e09ddff73a285f9860ae19c1a2f0a9e59a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 18 May 2026 20:27:15 +0000 Subject: [PATCH 15/22] chore(tests): remove redundant File import --- tests/uploads.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts index 33cd87e2..cab4aaef 100644 --- a/tests/uploads.test.ts +++ b/tests/uploads.test.ts @@ -1,7 +1,6 @@ import fs from 'fs'; import type { ResponseLike } from 'writer-sdk/internal/to-file'; import { toFile } from 'writer-sdk/core/uploads'; -import { File } from 'node:buffer'; class MyClass { name: string = 'foo'; From c4f21edee4915b5e8d0c757dd6de75c2627d79bd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Mon, 18 May 2026 21:24:19 +0000 Subject: [PATCH 16/22] fix(typescript): upgrade tsc-multi so that it works with Node 26 --- package.json | 2 +- packages/mcp-server/package.json | 2 +- packages/mcp-server/yarn.lock | 6 +++--- yarn.lock | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 8419e108..f7a5f64a 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "publint": "^0.2.12", "ts-jest": "^29.1.0", "ts-node": "^10.5.0", - "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", "tslib": "^2.8.1", "typescript": "5.8.3", diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 7faa371d..37b4a1e8 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -74,7 +74,7 @@ "ts-jest": "^29.1.0", "ts-morph": "^19.0.0", "ts-node": "^10.5.0", - "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz", "tsconfig-paths": "^4.0.0" }, "imports": { diff --git a/packages/mcp-server/yarn.lock b/packages/mcp-server/yarn.lock index f5c309e2..05aa4e17 100644 --- a/packages/mcp-server/yarn.lock +++ b/packages/mcp-server/yarn.lock @@ -3926,9 +3926,9 @@ ts-node@^10.5.0: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz": - version "1.1.9" - resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz#777f6f5d9e26bf0e94e5170990dd3a841d6707cd" +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz": + version "1.1.11" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz#010247051be13b55abdc98f787c017285149f4f2" dependencies: debug "^4.3.7" fast-glob "^3.3.2" diff --git a/yarn.lock b/yarn.lock index 216bebc8..4881e76b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3209,9 +3209,9 @@ ts-node@^10.5.0: v8-compile-cache-lib "^3.0.0" yn "3.1.1" -"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz": - version "1.1.9" - resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz#777f6f5d9e26bf0e94e5170990dd3a841d6707cd" +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz": + version "1.1.11" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz#010247051be13b55abdc98f787c017285149f4f2" dependencies: debug "^4.3.7" fast-glob "^3.3.2" From 5f3799dd90e31153b9e3c9f31e666e6f90c4ef5f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 20:16:32 +0000 Subject: [PATCH 17/22] fix: treat text/plan with format: binary as raw upload --- api.md | 2 +- packages/mcp-server/src/local-docs-search.ts | 6 +++--- src/resources/files.ts | 13 +++---------- tests/api-resources/files.test.ts | 6 ++---- 4 files changed, 9 insertions(+), 18 deletions(-) diff --git a/api.md b/api.md index 97acf2cd..30c4d049 100644 --- a/api.md +++ b/api.md @@ -133,7 +133,7 @@ Methods: - client.files.delete(fileID) -> FileDeleteResponse - client.files.download(fileID) -> Response - client.files.retry({ ...params }) -> FileRetryResponse -- client.files.upload({ ...params }) -> File +- client.files.upload(content, { ...params }) -> File # Tools diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts index 7e66adaf..8cc33329 100644 --- a/packages/mcp-server/src/local-docs-search.ts +++ b/packages/mcp-server/src/local-docs-search.ts @@ -915,12 +915,12 @@ const EMBEDDED_METHODS: MethodEntry[] = [ params: ['content: string;', 'Content-Disposition: string;', 'graphId?: string;'], response: '{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }', markdown: - "## upload\n\n`client.files.upload(content: string, Content-Disposition: string, graphId?: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**post** `/v1/files`\n\nUpload a new file to the system. Supports various file formats including PDF, DOC, DOCX, PPT, PPTX, JPG, PNG, EML, HTML, SRT, CSV, XLS, and XLSX.\n\n### Parameters\n\n- `content: string`\n\n- `Content-Disposition: string`\n\n- `graphId?: string`\n The unique identifier of the Knowledge Graph to associate the uploaded file with.\n\nNote: The response from the upload endpoint does not include the `graphId` field, but the association will be visible when you retrieve the file using the file retrieval endpoint.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.upload({ content: fs.createReadStream('path/to/file'), 'Content-Disposition': 'Content-Disposition' });\n\nconsole.log(file);\n```", + "## upload\n\n`client.files.upload(content: string, Content-Disposition: string, graphId?: string): { id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n**post** `/v1/files`\n\nUpload a new file to the system. Supports various file formats including PDF, DOC, DOCX, PPT, PPTX, JPG, PNG, EML, HTML, SRT, CSV, XLS, and XLSX.\n\n### Parameters\n\n- `content: string`\n\n- `Content-Disposition: string`\n\n- `graphId?: string`\n The unique identifier of the Knowledge Graph to associate the uploaded file with.\n\nNote: The response from the upload endpoint does not include the `graphId` field, but the association will be visible when you retrieve the file using the file retrieval endpoint.\n\n### Returns\n\n- `{ id: string; created_at: string; graph_ids: string[]; name: string; status: string; }`\n\n - `id: string`\n - `created_at: string`\n - `graph_ids: string[]`\n - `name: string`\n - `status: string`\n\n### Example\n\n```typescript\nimport Writer from 'writer-sdk';\n\nconst client = new Writer();\n\nconst file = await client.files.upload(fs.createReadStream('path/to/file'), { 'Content-Disposition': 'Content-Disposition' });\n\nconsole.log(file);\n```", perLanguage: { typescript: { method: 'client.files.upload', example: - "import fs from 'fs';\nimport Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.upload({\n content: fs.createReadStream('path/to/file'),\n 'Content-Disposition': 'Content-Disposition',\n});\n\nconsole.log(file.id);", + "import Writer from 'writer-sdk';\n\nconst client = new Writer({\n apiKey: process.env['WRITER_API_KEY'], // This is the default and can be omitted\n});\n\nconst file = await client.files.upload(fs.createReadStream('path/to/file'), {\n 'Content-Disposition': 'Content-Disposition',\n});\n\nconsole.log(file.id);", }, python: { method: 'files.upload', @@ -930,7 +930,7 @@ const EMBEDDED_METHODS: MethodEntry[] = [ go: { method: 'client.Files.Upload', example: - 'package main\n\nimport (\n\t"bytes"\n\t"context"\n\t"fmt"\n\t"io"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Upload(context.TODO(), writersdk.FileUploadParams{\n\t\tContent: io.Reader(bytes.NewBuffer([]byte("Example data"))),\n\t\tContentDisposition: writersdk.F("Content-Disposition"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', + 'package main\n\nimport (\n\t"bytes"\n\t"context"\n\t"fmt"\n\t"io"\n\n\t"github.com/stainless-sdks/writer-go"\n\t"github.com/stainless-sdks/writer-go/option"\n)\n\nfunc main() {\n\tclient := writersdk.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tfile, err := client.Files.Upload(\n\t\tcontext.TODO(),\n\t\tio.Reader(bytes.NewBuffer([]byte("Example data"))),\n\t\twritersdk.FileUploadParams{\n\t\t\tContentDisposition: writersdk.F("Content-Disposition"),\n\t\t},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", file.ID)\n}\n', }, http: { example: diff --git a/src/resources/files.ts b/src/resources/files.ts index e5214069..c94a79fa 100644 --- a/src/resources/files.ts +++ b/src/resources/files.ts @@ -60,16 +60,14 @@ export class Files extends APIResource { * Upload a new file to the system. Supports various file formats including PDF, * DOC, DOCX, PPT, PPTX, JPG, PNG, EML, HTML, SRT, CSV, XLS, and XLSX. */ - upload(params: FileUploadParams, options?: RequestOptions): APIPromise { - const { - content, - 'Content-Disposition': contentDisposition, + upload(content: Uploadable, params: FileUploadParams, options?: RequestOptions): APIPromise { + const { 'Content-Disposition': contentDisposition, 'Content-Type': contentType, graphId, } = params; return this._client.post('/v1/files', { - query: { graphId }, body: content, + query: { graphId }, ...options, headers: buildHeaders([ { 'Content-Type': contentType, 'Content-Disposition': contentDisposition }, @@ -171,11 +169,6 @@ export interface FileRetryParams { } export interface FileUploadParams { - /** - * Body param - */ - content: Uploadable; - /** * Header param: The disposition type of the file, typically used to indicate the * form-data name. Use `attachment` with the filename parameter to specify the name diff --git a/tests/api-resources/files.test.ts b/tests/api-resources/files.test.ts index 895c0ee6..899bd855 100644 --- a/tests/api-resources/files.test.ts +++ b/tests/api-resources/files.test.ts @@ -76,8 +76,7 @@ describe('resource files', () => { // requests with binary data not yet supported in test environment test.skip('upload: only required params', async () => { - const responsePromise = client.files.upload({ - content: await toFile(Buffer.from('Example data'), 'README.md'), + const responsePromise = client.files.upload(await toFile(Buffer.from('Example data'), 'README.md'), { 'Content-Disposition': 'Content-Disposition', 'Content-Type': 'Content-Type', }); @@ -92,8 +91,7 @@ describe('resource files', () => { // requests with binary data not yet supported in test environment test.skip('upload: required and optional params', async () => { - const response = await client.files.upload({ - content: await toFile(Buffer.from('Example data'), 'README.md'), + const response = await client.files.upload(await toFile(Buffer.from('Example data'), 'README.md'), { 'Content-Disposition': 'Content-Disposition', 'Content-Type': 'Content-Type', graphId: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', From 88197ba9e896440696a46b21129b07862f90dc3c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 21:11:12 +0000 Subject: [PATCH 18/22] chore(internal): codegen related update --- yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/yarn.lock b/yarn.lock index 4881e76b..64b3a996 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1215,9 +1215,9 @@ baseline-browser-mapping@^2.9.0: integrity sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg== brace-expansion@^2.0.2: - version "2.1.0" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.0.tgz#4f41a41190216ee36067ec381526fe9539c4f0ae" - integrity sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w== + version "2.1.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.1.tgz#c68b1c4111c76aae3a6fba55d496cee10c39dad8" + integrity sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA== dependencies: balanced-match "^1.0.0" From 1e77ebcc14b5b7a82dcfe65fe0a1d7410d2e2288 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 28 May 2026 21:11:55 +0000 Subject: [PATCH 19/22] fix(mcp): use `pure-lockfile` when building mcp server --- scripts/build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build b/scripts/build index 30e0f598..8a4cfd0e 100755 --- a/scripts/build +++ b/scripts/build @@ -52,6 +52,6 @@ fi # build all sub-packages for dir in packages/*; do if [ -d "$dir" ]; then - (cd "$dir" && yarn install && yarn build) + (cd "$dir" && yarn install --pure-lockfile && yarn build) fi done From 98dbaa3d0295db2e5721b8bcc79980c171d88342 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 17:56:31 +0000 Subject: [PATCH 20/22] release: 3.0.0 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 35 +++++++++++++++++++++++++++++++ package.json | 2 +- packages/mcp-server/manifest.json | 2 +- packages/mcp-server/package.json | 2 +- packages/mcp-server/src/server.ts | 2 +- src/version.ts | 2 +- 7 files changed, 41 insertions(+), 6 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e601dc3f..d4f6f299 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "3.0.0-rc.1" + ".": "3.0.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 66a60d48..d73bb1b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,40 @@ # Changelog +## 3.0.0 (2026-06-02) + +Full Changelog: [v3.0.0-rc.1...v3.0.0](https://github.com/writer/writer-node/compare/v3.0.0-rc.1...v3.0.0) + +### Features + +* support setting headers via env ([775860c](https://github.com/writer/writer-node/commit/775860c7b034ec2b29133441ca42ff1653559737)) + + +### Bug Fixes + +* **mcp:** use `pure-lockfile` when building mcp server ([1e77ebc](https://github.com/writer/writer-node/commit/1e77ebcc14b5b7a82dcfe65fe0a1d7410d2e2288)) +* treat text/plan with format: binary as raw upload ([5f3799d](https://github.com/writer/writer-node/commit/5f3799dd90e31153b9e3c9f31e666e6f90c4ef5f)) +* **typescript:** upgrade tsc-multi so that it works with Node 26 ([c4f21ed](https://github.com/writer/writer-node/commit/c4f21edee4915b5e8d0c757dd6de75c2627d79bd)) + + +### Chores + +* avoid formatting file that gets changed during releases ([6a45720](https://github.com/writer/writer-node/commit/6a457206747179f91a6bd085e19b26b68d5caf99)) +* **format:** run eslint and prettier separately ([be7d4a0](https://github.com/writer/writer-node/commit/be7d4a0d88334afce883d534ca85d735aa026bc4)) +* **formatter:** run prettier and eslint separately ([b671b3d](https://github.com/writer/writer-node/commit/b671b3d852b2943f44140f8ccd827100e9121149)) +* **internal:** codegen related update ([88197ba](https://github.com/writer/writer-node/commit/88197ba9e896440696a46b21129b07862f90dc3c)) +* **internal:** codegen related update ([7f46854](https://github.com/writer/writer-node/commit/7f46854adff49ae46df71380fb8a40cd0879c4ae)) +* **internal:** more robust bootstrap script ([af77915](https://github.com/writer/writer-node/commit/af77915717a2749b0275b3fc9c1a09f4c69826ce)) +* **internal:** update docs ordering ([dec3f3d](https://github.com/writer/writer-node/commit/dec3f3d0198f8caf0ed3c0851d823ea130731cc8)) +* redact api-key headers in debug logs ([7b2b3a9](https://github.com/writer/writer-node/commit/7b2b3a92068d07ca8d292adfe1059870cbe5265d)) +* restructure docs search code ([6eeaf25](https://github.com/writer/writer-node/commit/6eeaf254b4afdffe9244423b9528dae85392db45)) +* **tests:** bump steady to v0.22.1 ([3a42ea2](https://github.com/writer/writer-node/commit/3a42ea27a588abc1ecf5ed6464ab83316eedfdc4)) +* **tests:** remove redundant File import ([c4c7f9e](https://github.com/writer/writer-node/commit/c4c7f9e09ddff73a285f9860ae19c1a2f0a9e59a)) + + +### Documentation + +* update http mcp docs ([34a1c2e](https://github.com/writer/writer-node/commit/34a1c2e84ada77d9b1d6aa3b94edcc9ebebc9244)) + ## 3.0.0-rc.1 (2026-04-13) Full Changelog: [v2.3.3-rc.1...v3.0.0-rc.1](https://github.com/writer/writer-node/compare/v2.3.3-rc.1...v3.0.0-rc.1) diff --git a/package.json b/package.json index f7a5f64a..4577ad04 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "writer-sdk", - "version": "3.0.0-rc.1", + "version": "3.0.0", "description": "The official TypeScript library for the Writer API", "author": "Writer ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/manifest.json b/packages/mcp-server/manifest.json index 423d6234..a870fd12 100644 --- a/packages/mcp-server/manifest.json +++ b/packages/mcp-server/manifest.json @@ -1,7 +1,7 @@ { "dxt_version": "0.2", "name": "writer-sdk-mcp", - "version": "3.0.0-rc.1", + "version": "3.0.0", "description": "The official MCP Server for the Writer API", "author": { "name": "Writer", diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 37b4a1e8..7b32ac90 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "writer-sdk-mcp", - "version": "3.0.0-rc.1", + "version": "3.0.0", "description": "The official MCP Server for the Writer API", "author": "Writer ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index f6b107b8..c57801b0 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -28,7 +28,7 @@ export const newMcpServer = async ({ new McpServer( { name: 'writer_sdk_api', - version: '3.0.0-rc.1', + version: '3.0.0', }, { instructions: await getInstructions({ stainlessApiKey, customInstructionsPath }), diff --git a/src/version.ts b/src/version.ts index 1e17ebcc..bccd5c23 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '3.0.0-rc.1'; // x-release-please-version +export const VERSION = '3.0.0'; // x-release-please-version From adf5ccb8d52080f03a8704e41d304b3838250376 Mon Sep 17 00:00:00 2001 From: Ashley Weaver Date: Tue, 2 Jun 2026 11:14:45 -0700 Subject: [PATCH 21/22] fix: Fix linting errors. --- examples/upload-and-attach-file-to-graph.ts | 3 +-- src/resources/files.ts | 5 +---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/examples/upload-and-attach-file-to-graph.ts b/examples/upload-and-attach-file-to-graph.ts index 45c47b91..5cfb1219 100755 --- a/examples/upload-and-attach-file-to-graph.ts +++ b/examples/upload-and-attach-file-to-graph.ts @@ -11,10 +11,9 @@ async function main() { description: 'This is a graph created from the SDK', }); - let file = await client.files.upload({ + let file = await client.files.upload(fs.createReadStream('examples/example.txt'), { 'Content-Type': 'text/plain', 'Content-Disposition': 'attachment; filename="example.txt"', - content: fs.createReadStream('examples/example.txt'), }); console.log(file.id); diff --git a/src/resources/files.ts b/src/resources/files.ts index c94a79fa..2fc92196 100644 --- a/src/resources/files.ts +++ b/src/resources/files.ts @@ -61,10 +61,7 @@ export class Files extends APIResource { * DOC, DOCX, PPT, PPTX, JPG, PNG, EML, HTML, SRT, CSV, XLS, and XLSX. */ upload(content: Uploadable, params: FileUploadParams, options?: RequestOptions): APIPromise { - const { 'Content-Disposition': contentDisposition, - 'Content-Type': contentType, - graphId, - } = params; + const { 'Content-Disposition': contentDisposition, 'Content-Type': contentType, graphId } = params; return this._client.post('/v1/files', { body: content, query: { graphId }, From 347354492d9f6a4211641b0db711e9b3f39c2af6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 18:19:14 +0000 Subject: [PATCH 22/22] release: 3.0.0 --- CHANGELOG.md | 271 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d73bb1b1..b7570184 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,277 @@ ## 3.0.0 (2026-06-02) +Full Changelog: [v3.0.0...v3.0.0](https://github.com/writer/writer-node/compare/v3.0.0...v3.0.0) + +### ⚠ BREAKING CHANGES + +* **mcp:** remove deprecated tool schemes +* **mcp:** **Migration:** To migrate, simply modify the command used to invoke the MCP server. Currently, the only supported tool scheme is code mode. Now, starting the server with just `node /path/to/mcp/server` or `npx package-name` will invoke code tools: changing your command to one of these is likely all you will need to do. + +### Features + +* **api:** add model graphs.Question ([#67](https://github.com/writer/writer-node/issues/67)) ([af195e9](https://github.com/writer/writer-node/commit/af195e9a6e4562dfb7a7e24cde19a20d45e8511f)) +* **api:** add new endpoints ([#94](https://github.com/writer/writer-node/issues/94)) ([b0dcac4](https://github.com/writer/writer-node/commit/b0dcac40bb742924828cc51fd2c8702ab509e9a1)) +* **api:** add streaming to application generation ([#122](https://github.com/writer/writer-node/issues/122)) ([c85d6c6](https://github.com/writer/writer-node/commit/c85d6c62e16d3b9f38b401d162ab144123413b55)) +* **api:** add streaming to kg question ([#101](https://github.com/writer/writer-node/issues/101)) ([0279ffc](https://github.com/writer/writer-node/commit/0279ffc13185a7cc4e34bcd5df0489b19bcd8b64)) +* **api:** add support for graphs and files endpoints ([#13](https://github.com/writer/writer-node/issues/13)) ([52f462c](https://github.com/writer/writer-node/commit/52f462c25a34a0876577bf7e02444e57b99bf7aa)) +* **api:** added method to generate applications content ([#43](https://github.com/writer/writer-node/issues/43)) ([09b2657](https://github.com/writer/writer-node/commit/09b26572e0b66f490cb5fef0ee3f0c0250ae9142)) +* **api:** api update ([#100](https://github.com/writer/writer-node/issues/100)) ([a7c6e10](https://github.com/writer/writer-node/commit/a7c6e10b93285a3c5a42ed468097bab2556d6be3)) +* **api:** api update ([#121](https://github.com/writer/writer-node/issues/121)) ([f4adda0](https://github.com/writer/writer-node/commit/f4adda020d78626ce8ddf24e87c866db24e4baaf)) +* **api:** api update ([#81](https://github.com/writer/writer-node/issues/81)) ([d61a1db](https://github.com/writer/writer-node/commit/d61a1db8343f7ca2d98de4ef66c16020b2d7144b)) +* **api:** api update ([#84](https://github.com/writer/writer-node/issues/84)) ([dfbb999](https://github.com/writer/writer-node/commit/dfbb9998ef58cf008ad4ec920fc387050ee37153)) +* **api:** api update ([#87](https://github.com/writer/writer-node/issues/87)) ([eabef89](https://github.com/writer/writer-node/commit/eabef89d3b32f0a46e546e004d16d91f3b91e63c)) +* **api:** default timeout increase to 3 min ([#111](https://github.com/writer/writer-node/issues/111)) ([e0d48dc](https://github.com/writer/writer-node/commit/e0d48dc70007e2ff26f7045ee5362d8954328805)) +* **api:** Deprecate AI Detection, Medical Comprehend, and Context-Aware Text Splitting ([91097e4](https://github.com/writer/writer-node/commit/91097e4d5d1165e5f8d422b475389b34e9371349)) +* **api:** manual updates ([0012f4c](https://github.com/writer/writer-node/commit/0012f4ccc4acda716ef0559edc28f14af57911fa)) +* **api:** manual updates ([d9dd552](https://github.com/writer/writer-node/commit/d9dd55266323cb77cb8d4b88b6cc3ff3c7a91a00)) +* **api:** manual updates ([#102](https://github.com/writer/writer-node/issues/102)) ([eea7dcc](https://github.com/writer/writer-node/commit/eea7dcc7d88ebe666cce615991b302dfec62d46b)) +* **api:** manual updates ([#105](https://github.com/writer/writer-node/issues/105)) ([9158a6d](https://github.com/writer/writer-node/commit/9158a6debe889e7cc7cf23df00d5f46671d352e7)) +* **api:** manual updates ([#119](https://github.com/writer/writer-node/issues/119)) ([37f2a16](https://github.com/writer/writer-node/commit/37f2a169c41b4b0a22d7bcff562f6881a66f3af9)) +* **api:** manual updates ([#62](https://github.com/writer/writer-node/issues/62)) ([d9dedc4](https://github.com/writer/writer-node/commit/d9dedc400a225420ef23bbd2bc0077a1cac59ba5)) +* **api:** manual updates ([#64](https://github.com/writer/writer-node/issues/64)) ([d072c4d](https://github.com/writer/writer-node/commit/d072c4d279ee25087b282404a097fa80a1f7d17c)) +* **api:** manual updates ([#95](https://github.com/writer/writer-node/issues/95)) ([26f13bd](https://github.com/writer/writer-node/commit/26f13bda1f456ff17cb8194cf5c2edeb6303652b)) +* **api:** OpenAPI spec update via Stainless API ([#11](https://github.com/writer/writer-node/issues/11)) ([e742ffe](https://github.com/writer/writer-node/commit/e742ffeb02c8cbee7abee98e70c7ca6673770b85)) +* **api:** OpenAPI spec update via Stainless API ([#19](https://github.com/writer/writer-node/issues/19)) ([00d9929](https://github.com/writer/writer-node/commit/00d9929fea595070b9e0e3e6042b40f0d6f898cf)) +* **api:** OpenAPI spec update via Stainless API ([#22](https://github.com/writer/writer-node/issues/22)) ([b3b9223](https://github.com/writer/writer-node/commit/b3b9223530de5b8c65bc3e0c58869a8a4a140d3b)) +* **api:** OpenAPI spec update via Stainless API ([#23](https://github.com/writer/writer-node/issues/23)) ([1e9c082](https://github.com/writer/writer-node/commit/1e9c08252bf0987fa7e0830bfaa5db6d306cc405)) +* **api:** OpenAPI spec update via Stainless API ([#25](https://github.com/writer/writer-node/issues/25)) ([cc8dca0](https://github.com/writer/writer-node/commit/cc8dca08fa4c6b0adcb8fb921a7741e0e78e3934)) +* **api:** rename kg question and add text-to-graph ([#103](https://github.com/writer/writer-node/issues/103)) ([5e651e2](https://github.com/writer/writer-node/commit/5e651e2383975474a8dea114527c4111e01f9b2d)) +* **api:** rename to chat_completion_chunk ([#73](https://github.com/writer/writer-node/issues/73)) ([e4d5ac4](https://github.com/writer/writer-node/commit/e4d5ac4a9cf5eb8fa8a068024628b4ae689e5468)) +* **api:** update models in readme ([#79](https://github.com/writer/writer-node/issues/79)) ([19b7851](https://github.com/writer/writer-node/commit/19b7851bc31035fb457063bd5ea92aa15f4bc4ee)) +* **api:** update tools api methods ([#99](https://github.com/writer/writer-node/issues/99)) ([991f955](https://github.com/writer/writer-node/commit/991f955a62816fbd25e92649f84383f264521755)) +* **api:** update via SDK Studio ([f0c7afd](https://github.com/writer/writer-node/commit/f0c7afd876cd809a1050bd6ca45ad23803c4475e)) +* **api:** update via SDK Studio ([a700263](https://github.com/writer/writer-node/commit/a700263a6a96e5b2fd42f4e177cc9a08393273d5)) +* **api:** update via SDK Studio ([4ea2214](https://github.com/writer/writer-node/commit/4ea2214221363c04a2fff5c4478d0e0e21c220dd)) +* **api:** update via SDK Studio ([b3c74ab](https://github.com/writer/writer-node/commit/b3c74ab04b2e8fadb6739969b8ceeee6d853fdaa)) +* **api:** update via SDK Studio ([f3018fc](https://github.com/writer/writer-node/commit/f3018fc9f6feb08d54b3a76f80681626c0083272)) +* **api:** update via SDK Studio ([b42882d](https://github.com/writer/writer-node/commit/b42882ddec15bab1f2c0897a8dc337fff5b96432)) +* **api:** update via SDK Studio ([27e23b1](https://github.com/writer/writer-node/commit/27e23b1d7856d7e172adf3879fdee397cf9c8048)) +* **api:** update via SDK Studio ([3504f6d](https://github.com/writer/writer-node/commit/3504f6dcf928563eaafd31ded2572d6c2e2f0530)) +* **api:** update via SDK Studio ([ad2a87f](https://github.com/writer/writer-node/commit/ad2a87f902a94a48ddfdfc8c6e1284dbf0ecdbe8)) +* **api:** update via SDK Studio ([#14](https://github.com/writer/writer-node/issues/14)) ([88e43b2](https://github.com/writer/writer-node/commit/88e43b271ffbf1130d6ed582bd8fb0c29bdbf4e1)) +* **api:** update via SDK Studio ([#15](https://github.com/writer/writer-node/issues/15)) ([11d170b](https://github.com/writer/writer-node/commit/11d170bf8649dca8beb99519ca0d12097bf28412)) +* **api:** update via SDK Studio ([#16](https://github.com/writer/writer-node/issues/16)) ([455b64a](https://github.com/writer/writer-node/commit/455b64ae3c138ae1befef9d20b317b686bf99133)) +* **api:** update via SDK Studio ([#17](https://github.com/writer/writer-node/issues/17)) ([fcd684d](https://github.com/writer/writer-node/commit/fcd684d35d9e66c8a7f85c515c22d50ce25c89ba)) +* **api:** update via SDK Studio ([#20](https://github.com/writer/writer-node/issues/20)) ([4f863a4](https://github.com/writer/writer-node/commit/4f863a424f73ec65d7075450de05f1fafbda22a6)) +* **api:** update via SDK Studio ([#21](https://github.com/writer/writer-node/issues/21)) ([19a6a2c](https://github.com/writer/writer-node/commit/19a6a2cc64b7f9900cead093521b5b6c3d17c29f)) +* **api:** update via SDK Studio ([#24](https://github.com/writer/writer-node/issues/24)) ([04c9642](https://github.com/writer/writer-node/commit/04c964230fb0a45b01bac545f1c3e4f5a0a1a7e9)) +* **api:** update via SDK Studio ([#3](https://github.com/writer/writer-node/issues/3)) ([514a183](https://github.com/writer/writer-node/commit/514a1831d625e4e536e5c1331f11f634dc78d977)) +* **api:** update via SDK Studio ([#37](https://github.com/writer/writer-node/issues/37)) ([978cf26](https://github.com/writer/writer-node/commit/978cf26ddca6e10cccbb36fb0a7e0eaa44ae367b)) +* **api:** update via SDK Studio ([#4](https://github.com/writer/writer-node/issues/4)) ([c57666a](https://github.com/writer/writer-node/commit/c57666a9bac97efdbc39fe3d4dc397ae4cfd83a3)) +* **api:** update via SDK Studio ([#41](https://github.com/writer/writer-node/issues/41)) ([6e08bc0](https://github.com/writer/writer-node/commit/6e08bc0d85946bda11b397bb647f32595992d322)) +* **api:** update via SDK Studio ([#42](https://github.com/writer/writer-node/issues/42)) ([2c54f4a](https://github.com/writer/writer-node/commit/2c54f4a8975a92d169beff5dbd9b096f7999e7b5)) +* **api:** update via SDK Studio ([#6](https://github.com/writer/writer-node/issues/6)) ([4e3a404](https://github.com/writer/writer-node/commit/4e3a404e9b208735519a190b21f987c1a0c258cc)) +* **api:** update via SDK Studio ([#7](https://github.com/writer/writer-node/issues/7)) ([8bacaeb](https://github.com/writer/writer-node/commit/8bacaebb0db6e46ad27f9d1e6b959d23708aa48b)) +* **client:** send retry count header ([#61](https://github.com/writer/writer-node/issues/61)) ([c0a3dde](https://github.com/writer/writer-node/commit/c0a3ddebb34f34567f01951f39bee1a144e2d05a)) +* feat: joint method `uploadAndAddFileToGraph` ([49ae4ba](https://github.com/writer/writer-node/commit/49ae4ba238ca5791e9df5ef42998fffe33e5c121)) +* fix: lint ([4a363dc](https://github.com/writer/writer-node/commit/4a363dc4869b1022e31367b6ddd42b4757ee479e)) +* fix(api/files): remove unintentional Content-Length header param ([00aa0e8](https://github.com/writer/writer-node/commit/00aa0e8d85f8c90d2923f506f650cb93dc8c1438)) +* **internal:** make git install file structure match npm ([#118](https://github.com/writer/writer-node/issues/118)) ([407d303](https://github.com/writer/writer-node/commit/407d303875b56668730be19459cf33441745c577)) +* joint method `uploadAndAddFileToGraph` ([d9e933a](https://github.com/writer/writer-node/commit/d9e933ad43c9808f175a84651333429a7d12272b)) +* **mcp:** add an option to disable code tool ([fa96ea5](https://github.com/writer/writer-node/commit/fa96ea5f1c6c863ee94918f58f532ecf7d4ec8c3)) +* **mcp:** add initial server instructions ([d52d098](https://github.com/writer/writer-node/commit/d52d098bfb5163f020f6bf7a0e45e1ea911ca962)) +* **mcp:** add typescript check to code execution tool ([7ecde82](https://github.com/writer/writer-node/commit/7ecde8204a6475dc8106c4c90d1e90030260e465)) +* **mcp:** handle code mode calls in the Stainless API ([a705a1b](https://github.com/writer/writer-node/commit/a705a1b8ed30c17464d0a3700c828796550ed8d6)) +* **mcp:** return logs on code tool errors ([76551d3](https://github.com/writer/writer-node/commit/76551d345f33dbe6f6ea1bc437b691bcf3690664)) +* support setting headers via env ([775860c](https://github.com/writer/writer-node/commit/775860c7b034ec2b29133441ca42ff1653559737)) + + +### Bug Fixes + +* add content type to file uploads param ([cb5531a](https://github.com/writer/writer-node/commit/cb5531ab082f648e26b41b109e56b84bd41b4c50)) +* **api/files:** remove unintentional Content-Length header param ([82e9f9b](https://github.com/writer/writer-node/commit/82e9f9ba2258b00b23b494336599792cc501ddb7)) +* change file content type to Core.Uploadable ([64c3ac9](https://github.com/writer/writer-node/commit/64c3ac9f330c55616511146bc4c2c228ebf05fc6)) +* **client:** avoid memory leak with abort signals ([325c9ca](https://github.com/writer/writer-node/commit/325c9ca844c64083fb0e09f83c291cc17ef2c61d)) +* **client:** avoid removing abort listener too early ([8a3f29d](https://github.com/writer/writer-node/commit/8a3f29dbe0af0d126d7227b500c551204c916773)) +* **client:** preserve URL params already embedded in path ([c650393](https://github.com/writer/writer-node/commit/c650393f8ea5e1ceebb4c903f69b78d85572279c)) +* **compat:** remove ReadableStream polyfill redundant since node v16 ([#33](https://github.com/writer/writer-node/issues/33)) ([2dac835](https://github.com/writer/writer-node/commit/2dac83558310169906d1057ad08f80ae9ec81272)) +* **docs/contributing:** correct pnpm link command ([edcceda](https://github.com/writer/writer-node/commit/edcceda07df649e2a6dfd80d1b220b8e17a1b3ea)) +* **docs:** fix mcp installation instructions for remote servers ([5248a83](https://github.com/writer/writer-node/commit/5248a83066782fedd9c97b4b6f78f476c2535d59)) +* Fix linting error ([dea914e](https://github.com/writer/writer-node/commit/dea914eeb246514c80ea2a1e69d79c4a8f0e7ef3)) +* Fix linting errors. ([adf5ccb](https://github.com/writer/writer-node/commit/adf5ccb8d52080f03a8704e41d304b3838250376)) +* Fix linting errors. ([#246](https://github.com/writer/writer-node/issues/246)) ([dea914e](https://github.com/writer/writer-node/commit/dea914eeb246514c80ea2a1e69d79c4a8f0e7ef3)) +* fix request delays for retrying to be more respectful of high requested delays ([b897aab](https://github.com/writer/writer-node/commit/b897aab23f199ac46e4fe6092fb3c1cbc0cbdb7d)) +* fix tool_choice schema ([d3ade29](https://github.com/writer/writer-node/commit/d3ade29281eaf5ffd94022e77313d8cfe96955e3)) +* lint ([18cf3c1](https://github.com/writer/writer-node/commit/18cf3c185780c9b7cf63137ae4dfb776f96b6723)) +* **lint:** format ([032bc59](https://github.com/writer/writer-node/commit/032bc59490e65b17137e26d965e481290fc2e526)) +* **mcp:** add client instantiation options to code tool ([761c3b1](https://github.com/writer/writer-node/commit/761c3b1ccc0eacc6b7ed7782fd1abddefc9020d7)) +* **mcp:** allow falling back for required env variables ([7e8d2fc](https://github.com/writer/writer-node/commit/7e8d2fc3c1012493584dab21e31c36e0f458b3fd)) +* **mcp:** correct code tool API endpoint ([6cd6857](https://github.com/writer/writer-node/commit/6cd6857db708dc98d8ee76b3b324c1a123de222c)) +* **mcp:** correct code tool api output types ([9b088bc](https://github.com/writer/writer-node/commit/9b088bc1c7705c55bfb6f448f85520171a0ae820)) +* **mcp:** fix env parsing ([a8328e7](https://github.com/writer/writer-node/commit/a8328e7d7dc8abae15fe7c8bb653e206a14c51cd)) +* **mcp:** fix options parsing ([6690d22](https://github.com/writer/writer-node/commit/6690d22af5aac3cdc2ffd883010b06989e6a4f92)) +* **mcp:** initialize SDK lazily to avoid failing the connection on init errors ([49df35f](https://github.com/writer/writer-node/commit/49df35fc62598b6ccc91e4e45cf5afa530c4f19d)) +* **mcp:** pass base url to code tool ([59063c0](https://github.com/writer/writer-node/commit/59063c0bea7c292d3bc080b32b8bfd92316446e5)) +* **mcp:** return correct lines on typescript errors ([c7e0c9b](https://github.com/writer/writer-node/commit/c7e0c9bffca2893dd36715811ba3b6001fa5544d)) +* **mcp:** return tool execution error on api error ([b62c6ba](https://github.com/writer/writer-node/commit/b62c6ba071ea931ae3af7b996b084403be6b0777)) +* **mcp:** update code tool prompt ([382ffb1](https://github.com/writer/writer-node/commit/382ffb1f2535c072fc1def53a0eb1e1456b609b9)) +* **mcp:** update prompt ([dddad93](https://github.com/writer/writer-node/commit/dddad93a9b1c3ab92f1d52a5bdbe31af46939d8e)) +* **mcp:** use `pure-lockfile` when building mcp server ([1e77ebc](https://github.com/writer/writer-node/commit/1e77ebcc14b5b7a82dcfe65fe0a1d7410d2e2288)) +* treat text/plan with format: binary as raw upload ([5f3799d](https://github.com/writer/writer-node/commit/5f3799dd90e31153b9e3c9f31e666e6f90c4ef5f)) +* **typescript:** upgrade tsc-multi so that it works with Node 26 ([c4f21ed](https://github.com/writer/writer-node/commit/c4f21edee4915b5e8d0c757dd6de75c2627d79bd)) +* **types:** remove leftover polyfill usage ([#60](https://github.com/writer/writer-node/issues/60)) ([043939d](https://github.com/writer/writer-node/commit/043939d96fdd8179fc56ff3b3ed48f37a91d724e)) +* **uploads:** avoid making redundant memory copies ([#55](https://github.com/writer/writer-node/issues/55)) ([f864fb3](https://github.com/writer/writer-node/commit/f864fb33da970311e3ef32cac083ba5543fe6a7c)) + + +### Chores + +* avoid formatting file that gets changed during releases ([6a45720](https://github.com/writer/writer-node/commit/6a457206747179f91a6bd085e19b26b68d5caf99)) +* break long lines in snippets into multiline ([58a37e3](https://github.com/writer/writer-node/commit/58a37e30f60599207bdc756ba723d25686770d4a)) +* **ci:** bump prism mock server version ([#47](https://github.com/writer/writer-node/issues/47)) ([3b881e9](https://github.com/writer/writer-node/commit/3b881e99f6d06d964f6b3d5c2321b2731ad8f0b3)) +* **ci:** escape input path in publish-npm workflow ([5a5bf6b](https://github.com/writer/writer-node/commit/5a5bf6b7c85abbc390ed796347b77855d8f5a461)) +* **ci:** minor changes ([#46](https://github.com/writer/writer-node/issues/46)) ([2cab651](https://github.com/writer/writer-node/commit/2cab65110b303808962dfa4f8378ca0d2e40aa0b)) +* **ci:** skip lint on metadata-only changes ([01c3e15](https://github.com/writer/writer-node/commit/01c3e15869a06fd6247270c6d6f2bc77ebbefd26)) +* **ci:** skip uploading artifacts on stainless-internal branches ([51bf9fc](https://github.com/writer/writer-node/commit/51bf9fc60afb36994efbac0e9bc04e39a2b5b163)) +* **ci:** upgrade `actions/github-script` ([c84c7b9](https://github.com/writer/writer-node/commit/c84c7b9ebc03fcee7411719aa5fd783cbdcdc38c)) +* **client:** do not parse responses with empty content-length ([6802838](https://github.com/writer/writer-node/commit/6802838d8eab0322f78ba8f2612aa282687715c9)) +* **client:** restructure abort controller binding ([3204f51](https://github.com/writer/writer-node/commit/3204f51e093c5f1390cef993d2a377b778edbe1d)) +* **docs:** fix incorrect client var names ([#34](https://github.com/writer/writer-node/issues/34)) ([186a9d9](https://github.com/writer/writer-node/commit/186a9d9816a8b1021203958aeaebc5954ce95c25)) +* fix example snippet imports ([4e80d76](https://github.com/writer/writer-node/commit/4e80d762dfb7537a347bcb7ea12a553f97d72f5b)) +* fix typo in descriptions ([2f6c30f](https://github.com/writer/writer-node/commit/2f6c30f7e0a9f56641eeb077fdda5abf79c9e11c)) +* **format:** run eslint and prettier separately ([be7d4a0](https://github.com/writer/writer-node/commit/be7d4a0d88334afce883d534ca85d735aa026bc4)) +* **formatter:** run prettier and eslint separately ([b671b3d](https://github.com/writer/writer-node/commit/b671b3d852b2943f44140f8ccd827100e9121149)) +* go live ([#1](https://github.com/writer/writer-node/issues/1)) ([97d56db](https://github.com/writer/writer-node/commit/97d56db208b49ffc17c8d54c52cdd8fc53699fa7)) +* **internal/client:** fix form-urlencoded requests ([69d4765](https://github.com/writer/writer-node/commit/69d476512384faa4ba6f068921c0aacb2fcd8c54)) +* **internal:** add constant for default timeout ([#36](https://github.com/writer/writer-node/issues/36)) ([b4220e2](https://github.com/writer/writer-node/commit/b4220e2d2ad266040c753b4c42f1f0da1a51a166)) +* **internal:** add health check to MCP server when running in HTTP mode ([cbb4461](https://github.com/writer/writer-node/commit/cbb44616abd6e800f622b8e2e1a406f5da72c85b)) +* **internal:** allow basic filtering of methods allowed for MCP code mode ([a07d4aa](https://github.com/writer/writer-node/commit/a07d4aaa8dcf25a61de3721f0203b26fac082ea0)) +* **internal:** allow setting x-stainless-api-key header on mcp server requests ([ec7acc0](https://github.com/writer/writer-node/commit/ec7acc08393eb40ab704817b28ac441a25747ff0)) +* **internal:** always generate MCP server dockerfiles and upgrade associated dependencies ([dc3398b](https://github.com/writer/writer-node/commit/dc3398b32e6139cb085ec0b1291e068d71cd35cf)) +* **internal:** avoid type checking errors with ts-reset ([d32477d](https://github.com/writer/writer-node/commit/d32477dbfdf57bcd09bc40722698fad93b31fbde)) +* **internal:** bump @modelcontextprotocol/sdk, @hono/node-server, and minimatch ([85c4851](https://github.com/writer/writer-node/commit/85c4851f99e0cf1c918e6ffaec248dddffcecb77)) +* **internal:** bump cross-spawn to v7.0.6 ([#124](https://github.com/writer/writer-node/issues/124)) ([b5ccd7c](https://github.com/writer/writer-node/commit/b5ccd7cfba653cd078769eef9900933fed84819f)) +* **internal:** cache fetch instruction calls in MCP server ([6745b11](https://github.com/writer/writer-node/commit/6745b119635f4fb1adc214136afb028beaf617e7)) +* **internal:** codegen related update ([88197ba](https://github.com/writer/writer-node/commit/88197ba9e896440696a46b21129b07862f90dc3c)) +* **internal:** codegen related update ([7f46854](https://github.com/writer/writer-node/commit/7f46854adff49ae46df71380fb8a40cd0879c4ae)) +* **internal:** codegen related update ([c959300](https://github.com/writer/writer-node/commit/c95930084716f047fd69d97c0d6314da95dc8ae4)) +* **internal:** codegen related update ([f120aae](https://github.com/writer/writer-node/commit/f120aaee36cb691f3be43210e34324982b51805d)) +* **internal:** codegen related update ([757eeae](https://github.com/writer/writer-node/commit/757eeae33e139f642cdb432b600c7c6887e65f25)) +* **internal:** codegen related update ([56fc7c7](https://github.com/writer/writer-node/commit/56fc7c7870a26529558d4ae70d238d201e2015a0)) +* **internal:** codegen related update ([e12403b](https://github.com/writer/writer-node/commit/e12403bc7c73a4ae453c9bfbab7a5423a91497e7)) +* **internal:** codegen related update ([1be7281](https://github.com/writer/writer-node/commit/1be72815af2ad70591cfc3a0c63bbf318d5dc405)) +* **internal:** codegen related update ([4807744](https://github.com/writer/writer-node/commit/4807744a4ec789fa0e283d33fa77b50a9f9880fc)) +* **internal:** codegen related update ([e56fb21](https://github.com/writer/writer-node/commit/e56fb21f84394e9f58fadcfaa86b1e52ab8f4673)) +* **internal:** codegen related update ([c549df2](https://github.com/writer/writer-node/commit/c549df28775dfec7ec1367b854068d9d845b851d)) +* **internal:** codegen related update ([220705b](https://github.com/writer/writer-node/commit/220705bccf50e9c1a2c0c087a697e274a64e090c)) +* **internal:** codegen related update ([cf8a0ac](https://github.com/writer/writer-node/commit/cf8a0ac27f7a4d3c2f09435d537a0e9b6d5f7a95)) +* **internal:** codegen related update ([5958ab9](https://github.com/writer/writer-node/commit/5958ab937e37a09fe325dfc509537080825573e0)) +* **internal:** codegen related update ([30d1025](https://github.com/writer/writer-node/commit/30d10259e89332dd11656dbefbee651eeb506706)) +* **internal:** codegen related update ([#116](https://github.com/writer/writer-node/issues/116)) ([d632f68](https://github.com/writer/writer-node/commit/d632f686120b920e06dfa7a2dc76ddf651da7357)) +* **internal:** codegen related update ([#31](https://github.com/writer/writer-node/issues/31)) ([c3ba095](https://github.com/writer/writer-node/commit/c3ba0959665d5604bc963b16c6ab71f738686504)) +* **internal:** codegen related update ([#45](https://github.com/writer/writer-node/issues/45)) ([5c54eb9](https://github.com/writer/writer-node/commit/5c54eb96d4bfcaa305990be63ef98839679ac56d)) +* **internal:** codegen related update ([#48](https://github.com/writer/writer-node/issues/48)) ([d908809](https://github.com/writer/writer-node/commit/d9088094ecd095db6f598384dbda4bd1f01ce460)) +* **internal:** codegen related update ([#49](https://github.com/writer/writer-node/issues/49)) ([d057479](https://github.com/writer/writer-node/commit/d05747974f065d73ffa6c19c792292fd626b87d8)) +* **internal:** codegen related update ([#51](https://github.com/writer/writer-node/issues/51)) ([fcebf50](https://github.com/writer/writer-node/commit/fcebf50518f24dd765d675b94afd3937ac66dd5b)) +* **internal:** codegen related update ([#58](https://github.com/writer/writer-node/issues/58)) ([0b0a85d](https://github.com/writer/writer-node/commit/0b0a85d7d4be783fbd9a674ed1d3bc961e313b94)) +* **internal:** codegen related update ([#69](https://github.com/writer/writer-node/issues/69)) ([4fdbf70](https://github.com/writer/writer-node/commit/4fdbf70757530bd9dfd045e60da042877aac82a4)) +* **internal:** codegen related update ([#72](https://github.com/writer/writer-node/issues/72)) ([611a33b](https://github.com/writer/writer-node/commit/611a33bda7ce33ec69fa3907a2b6ad7ae0fbe781)) +* **internal:** dependency updates ([#53](https://github.com/writer/writer-node/issues/53)) ([ab3c399](https://github.com/writer/writer-node/commit/ab3c399044f36aa74f21148770869c034c4185ab)) +* **internal:** fix MCP docker image builds in yarn projects ([4a40b93](https://github.com/writer/writer-node/commit/4a40b93b9a76b15213e3b890686f806e301e2328)) +* **internal:** fix MCP Dockerfiles so they can be built without buildkit ([2e39b4f](https://github.com/writer/writer-node/commit/2e39b4fa5f4ee2554f2185a0466933e7414eccec)) +* **internal:** fix MCP Dockerfiles so they can be built without buildkit ([2aa7960](https://github.com/writer/writer-node/commit/2aa7960f102438b8b9a312bd32a1ddb1cb67b790)) +* **internal:** fix MCP server import ordering ([1a45a48](https://github.com/writer/writer-node/commit/1a45a48cde1f9961ac2f79d6bc775b1a607f0436)) +* **internal:** fix MCP server TS errors that occur with required client options ([64520aa](https://github.com/writer/writer-node/commit/64520aa474771c608f1a575d0cd9ae36bdca033c)) +* **internal:** fix pagination internals not accepting option promises ([302c9ab](https://github.com/writer/writer-node/commit/302c9ab7a966a1cc9e3f46a376057ab0d479ee83)) +* **internal:** improve layout of generated MCP server files ([da6f525](https://github.com/writer/writer-node/commit/da6f525158745577a74376c352bb967515e0f902)) +* **internal:** improve local docs search for MCP servers ([bf2441f](https://github.com/writer/writer-node/commit/bf2441f89a2d2642dcfb5978938518a3dba7ad15)) +* **internal:** improve local docs search for MCP servers ([d1710b0](https://github.com/writer/writer-node/commit/d1710b03fc4b42bdc8cab7dc288bea9eb084af71)) +* **internal:** make generated MCP servers compatible with Cloudflare worker environments ([d8af505](https://github.com/writer/writer-node/commit/d8af505573509dfa5541cb49021e7279850cd457)) +* **internal:** make MCP code execution location configurable via a flag ([8b197f0](https://github.com/writer/writer-node/commit/8b197f0e9406fc38ac7b318836484982b6b895a7)) +* **internal:** more robust bootstrap script ([af77915](https://github.com/writer/writer-node/commit/af77915717a2749b0275b3fc9c1a09f4c69826ce)) +* **internal:** move LineDecoder to a separate file ([#76](https://github.com/writer/writer-node/issues/76)) ([f8c8855](https://github.com/writer/writer-node/commit/f8c885507286f008fb26a501d692d25f912b4798)) +* **internal:** move stringifyQuery implementation to internal function ([08e2c09](https://github.com/writer/writer-node/commit/08e2c09ebe73f6c62b9d9b531662ff7827c7aa64)) +* **internal:** pass props through internal parser ([#78](https://github.com/writer/writer-node/issues/78)) ([bb1aae5](https://github.com/writer/writer-node/commit/bb1aae50a38e375118b3ddaf35ceabb83b0ae44d)) +* **internal:** refactor flag parsing for MCP servers and add debug flag ([5291a9f](https://github.com/writer/writer-node/commit/5291a9f086f73589f86a3a6bd604e6686e961f13)) +* **internal:** remove unnecessary getRequestClient function ([#123](https://github.com/writer/writer-node/issues/123)) ([8e9e6f0](https://github.com/writer/writer-node/commit/8e9e6f02a09bf3c31bdeb0c616ab51800696d2ed)) +* **internal:** show error causes in MCP servers when running in local mode ([6faf2cc](https://github.com/writer/writer-node/commit/6faf2cc413f92b3b0ae150251ecc63cc731bf07a)) +* **internal:** support custom-instructions-path flag in MCP servers ([8d2f3d0](https://github.com/writer/writer-node/commit/8d2f3d0fae360c5d3ae00fe48376e570e1904731)) +* **internal:** support local docs search in MCP servers ([f479ec6](https://github.com/writer/writer-node/commit/f479ec6f4141d7c59cf0dd44dff9fdf38debd2f4)) +* **internal:** support oauth authorization code flow for MCP servers ([96ba350](https://github.com/writer/writer-node/commit/96ba350f38776d9622a9cc4124ebca788a5fa9e1)) +* **internal:** support type annotations when running MCP in local execution mode ([7282ea3](https://github.com/writer/writer-node/commit/7282ea3eb7f9c0579ed0d7c14ed3585612b8d381)) +* **internal:** support x-stainless-mcp-client-envs header in MCP servers ([29ec150](https://github.com/writer/writer-node/commit/29ec150c6869179932be3ac434fc3596a2883387)) +* **internal:** support x-stainless-mcp-client-permissions headers in MCP servers ([5cacf5f](https://github.com/writer/writer-node/commit/5cacf5ff4671398607b6dcb56414c43a20bd77b8)) +* **internal:** switch MCP servers to use pino for logging ([a2693a7](https://github.com/writer/writer-node/commit/a2693a734be31a23d6f3156fd93c33a0a272a55c)) +* **internal:** tweak CI branches ([700bb90](https://github.com/writer/writer-node/commit/700bb904c404df16bd4e6c7635c7ab4de1ced843)) +* **internal:** update `actions/checkout` version ([ac62b27](https://github.com/writer/writer-node/commit/ac62b278b1aa8635c85e4b7f80dfd461c76bbde9)) +* **internal:** update dependencies to address dependabot vulnerabilities ([96b9468](https://github.com/writer/writer-node/commit/96b9468dddad4693959b59bd4dfd0c64e6948def)) +* **internal:** update docs ordering ([dec3f3d](https://github.com/writer/writer-node/commit/dec3f3d0198f8caf0ed3c0851d823ea130731cc8)) +* **internal:** update gitignore ([a8a8b44](https://github.com/writer/writer-node/commit/a8a8b44016b44b27e31cd36b7d4c3d726c0994f5)) +* **internal:** update isAbsoluteURL ([#126](https://github.com/writer/writer-node/issues/126)) ([0a676eb](https://github.com/writer/writer-node/commit/0a676eba5b7a8330fe6b196e362c105d8f3049c6)) +* **internal:** update lock file ([8872b80](https://github.com/writer/writer-node/commit/8872b80dddc9edf1d45de5387acce00b13e6010c)) +* **internal:** update multipart form array serialization ([5be2c2b](https://github.com/writer/writer-node/commit/5be2c2beea67491dcf0fe54ec757a049daa5e05b)) +* **internal:** upgrade @modelcontextprotocol/sdk and hono ([e62fb6c](https://github.com/writer/writer-node/commit/e62fb6c36372a4ece5574a2075248213641f9a50)) +* **internal:** upgrade babel, qs, js-yaml ([5717a02](https://github.com/writer/writer-node/commit/5717a02433ce869ff16eddce1a30b892667b37d5)) +* **internal:** upgrade eslint ([4ae73b1](https://github.com/writer/writer-node/commit/4ae73b119027a678183ab79ddef25703584f63b7)) +* **internal:** use link instead of file in MCP server package.json files ([245c089](https://github.com/writer/writer-node/commit/245c089021989cd21c8d418c2b846e34780b00db)) +* **internal:** use x-stainless-mcp-client-envs header for MCP remote code tool calls ([368815e](https://github.com/writer/writer-node/commit/368815effa9872d7cfb68b6b59fc2a3c292d3642)) +* **internal:** version bump ([#113](https://github.com/writer/writer-node/issues/113)) ([37a3f70](https://github.com/writer/writer-node/commit/37a3f705d82f14269e925377dc09d9869a653dc8)) +* **internal:** version bump ([#115](https://github.com/writer/writer-node/issues/115)) ([9309158](https://github.com/writer/writer-node/commit/930915807369000620132d52c5f45df6bd3462fb)) +* **internal:** version bump ([#28](https://github.com/writer/writer-node/issues/28)) ([254dd3c](https://github.com/writer/writer-node/commit/254dd3cc6595271fc239b42e2a8d2ebb683f7a9a)) +* **internal:** version bump ([#9](https://github.com/writer/writer-node/issues/9)) ([e8cc802](https://github.com/writer/writer-node/commit/e8cc8027b3ae9a9c7e25e932bb5815758b923017)) +* **mcp-server:** add support for session id, forward client info ([9fa5781](https://github.com/writer/writer-node/commit/9fa5781db92bbc1d576f0a6e2224368e9c526137)) +* **mcp-server:** improve instructions ([50343c5](https://github.com/writer/writer-node/commit/50343c59ca40bf64eb6d0fc315af953bced30f97)) +* **mcp-server:** increase local docs search result count from 5 to 10 ([f87e6b9](https://github.com/writer/writer-node/commit/f87e6b98513143c4570ab640361262109f507966)) +* **mcp-server:** log client info ([a946922](https://github.com/writer/writer-node/commit/a9469221dba5e55d923db1d7e5f11cf1bb1cbf6e)) +* **mcp-server:** return access instructions for 404 without API key ([30ceb2d](https://github.com/writer/writer-node/commit/30ceb2d5135fd4d2a17ba9ab6041d32573405b60)) +* **mcp:** add intent param to execute tool ([c988c65](https://github.com/writer/writer-node/commit/c988c65c5ac29240540265630b0b2c9a565caa94)) +* **mcp:** correctly update version in sync with sdk ([b93d491](https://github.com/writer/writer-node/commit/b93d491022f90f2f6b92bab112676e5df18bf4c2)) +* **mcp:** forward STAINLESS_API_KEY to docs search endpoint ([dde1184](https://github.com/writer/writer-node/commit/dde11849b78e009db7128c811b0f511f442801ae)) +* **mcp:** pass intent param to execute handler ([58fa431](https://github.com/writer/writer-node/commit/58fa4314badfa5ba2cd2cf148ffb46227d965389)) +* **mcp:** remove deprecated tool schemes ([e376d65](https://github.com/writer/writer-node/commit/e376d65638ff29ccef3339c53b61c6207a3c08d2)) +* **mcp:** up tsconfig lib version to es2022 ([cb421df](https://github.com/writer/writer-node/commit/cb421dfbb23c198f7bd3b39d6555c6e22ec0a200)) +* **mcp:** update lockfile ([8d1106e](https://github.com/writer/writer-node/commit/8d1106e94062b4610f8e0333761f82749c0bbc9f)) +* **mcp:** upgrade dependencies ([5766d6c](https://github.com/writer/writer-node/commit/5766d6c58f52a74fcfc718fa92e46a4a0e0103d7)) +* rebuild project due to codegen change ([#104](https://github.com/writer/writer-node/issues/104)) ([e1c82c3](https://github.com/writer/writer-node/commit/e1c82c3fcaa679478ed321bf97cf8935ed98e7d6)) +* rebuild project due to codegen change ([#107](https://github.com/writer/writer-node/issues/107)) ([f053183](https://github.com/writer/writer-node/commit/f0531839142b957f8e6574a654eceb82c9f7a4e0)) +* rebuild project due to codegen change ([#109](https://github.com/writer/writer-node/issues/109)) ([7f35e1b](https://github.com/writer/writer-node/commit/7f35e1b0c9574e02273130e99d56f99829ff7062)) +* rebuild project due to codegen change ([#110](https://github.com/writer/writer-node/issues/110)) ([fc9e0e0](https://github.com/writer/writer-node/commit/fc9e0e088f76f18055213deaf259381b7713b415)) +* rebuild project due to codegen change ([#90](https://github.com/writer/writer-node/issues/90)) ([89fa5b3](https://github.com/writer/writer-node/commit/89fa5b3b669fc430ab3578a126cffd4b536bcbd2)) +* rebuild project due to codegen change ([#91](https://github.com/writer/writer-node/issues/91)) ([3657edb](https://github.com/writer/writer-node/commit/3657edb012dac0612aef8d09944a0283718988e2)) +* rebuild project due to codegen change ([#92](https://github.com/writer/writer-node/issues/92)) ([a60408e](https://github.com/writer/writer-node/commit/a60408e45c1eae74b653e3f4b7120e461f9e29a0)) +* rebuild project due to codegen change ([#93](https://github.com/writer/writer-node/issues/93)) ([0f9276c](https://github.com/writer/writer-node/commit/0f9276cfecc4d48ded3536dfb6075636f298fc4f)) +* rebuild project due to codegen change ([#96](https://github.com/writer/writer-node/issues/96)) ([25327f5](https://github.com/writer/writer-node/commit/25327f5a7c98774387f100155428a291acd82f46)) +* rebuild project due to codegen change ([#97](https://github.com/writer/writer-node/issues/97)) ([6df076b](https://github.com/writer/writer-node/commit/6df076b5af13422cb960d602b6aeb174e6bbdbc9)) +* rebuild project due to codegen change ([#98](https://github.com/writer/writer-node/issues/98)) ([890c742](https://github.com/writer/writer-node/commit/890c74292aadb14d39ccec510f115b5740badf31)) +* redact api-key headers in debug logs ([7b2b3a9](https://github.com/writer/writer-node/commit/7b2b3a92068d07ca8d292adfe1059870cbe5265d)) +* restructure docs search code ([6eeaf25](https://github.com/writer/writer-node/commit/6eeaf254b4afdffe9244423b9528dae85392db45)) +* **test:** do not count install time for mock server timeout ([a345373](https://github.com/writer/writer-node/commit/a3453738634b2bcccde87fd0e9736eb1356ee45f)) +* **tests:** bump steady to v0.19.4 ([dad22a4](https://github.com/writer/writer-node/commit/dad22a4cd08a9aaedc076023093519f9b4813d87)) +* **tests:** bump steady to v0.19.5 ([b51c69d](https://github.com/writer/writer-node/commit/b51c69df9ec75a75a86560ddfa23ecb908dd5ff7)) +* **tests:** bump steady to v0.19.6 ([241c42d](https://github.com/writer/writer-node/commit/241c42d876331b92dee01b704d1eae1c0587f8f4)) +* **tests:** bump steady to v0.19.7 ([518baf9](https://github.com/writer/writer-node/commit/518baf98c314c1fe39c2d44e95863212f881f8b2)) +* **tests:** bump steady to v0.20.1 ([32f3fb9](https://github.com/writer/writer-node/commit/32f3fb9a4eebc6658ac077164f2eee9e21ddad00)) +* **tests:** bump steady to v0.20.2 ([b54c180](https://github.com/writer/writer-node/commit/b54c18011c29d415e55f7ccad2bfb0be46e3ba87)) +* **tests:** bump steady to v0.22.1 ([3a42ea2](https://github.com/writer/writer-node/commit/3a42ea27a588abc1ecf5ed6464ab83316eedfdc4)) +* **tests:** remove redundant File import ([c4c7f9e](https://github.com/writer/writer-node/commit/c4c7f9e09ddff73a285f9860ae19c1a2f0a9e59a)) +* **tests:** update prism version ([#32](https://github.com/writer/writer-node/issues/32)) ([6ea2f59](https://github.com/writer/writer-node/commit/6ea2f5920f53502b6ba5e0b7530aa22b0a1a620a)) +* **types:** nicer error class types + jsdocs ([#125](https://github.com/writer/writer-node/issues/125)) ([a94669a](https://github.com/writer/writer-node/commit/a94669a86363b394efc1d045144eff4c4e0ac257)) +* Update completions-streaming.ts ([303a7b4](https://github.com/writer/writer-node/commit/303a7b434686bed3e8b2ac4ddc68daa329ecf804)) +* update mock server docs ([b21d0a5](https://github.com/writer/writer-node/commit/b21d0a594a1ce7a8bf9db8f67af853f1dbefc16f)) +* update placeholder string ([95ae007](https://github.com/writer/writer-node/commit/95ae007e055d87d31ae11cbb2163ab5e882c20d5)) +* use latest @modelcontextprotocol/sdk ([08d8625](https://github.com/writer/writer-node/commit/08d8625b8b8a46b8b0f8bb92c6ee57be5b90a780)) + + +### Documentation + +* add pagination example ([#74](https://github.com/writer/writer-node/issues/74)) ([09b3ee2](https://github.com/writer/writer-node/commit/09b3ee23124d02bf223c1ec1e8458217af47b570)) +* **api:** updates to API spec ([535ef81](https://github.com/writer/writer-node/commit/535ef81a129dd3fb6c372079ff3a4af07e5861d2)) +* **api:** updates to API spec ([#44](https://github.com/writer/writer-node/issues/44)) ([5b3f183](https://github.com/writer/writer-node/commit/5b3f183754a6422212fba2175831ffcbb8470e8b)) +* **api:** updates to API spec ([#57](https://github.com/writer/writer-node/issues/57)) ([73dddc8](https://github.com/writer/writer-node/commit/73dddc829bc31141415005a762b0a3c16d1a852a)) +* **api:** updates to API spec ([#63](https://github.com/writer/writer-node/issues/63)) ([50a86f4](https://github.com/writer/writer-node/commit/50a86f4593fbcff313397279b32bb5ceb24fd471)) +* **api:** updates to API spec ([#70](https://github.com/writer/writer-node/issues/70)) ([7c0721d](https://github.com/writer/writer-node/commit/7c0721da2901bd6e4ee7aba97b32ec8b6d8bec52)) +* **api:** updates to API spec ([#75](https://github.com/writer/writer-node/issues/75)) ([3fad6c7](https://github.com/writer/writer-node/commit/3fad6c7738c5abf3e795f3b7d8c35d9a76eaf98b)) +* **api:** updates to API spec ([#77](https://github.com/writer/writer-node/issues/77)) ([8749431](https://github.com/writer/writer-node/commit/87494313a99d6c8be5f768ce7654bf7f52f7042a)) +* prominently feature MCP server setup in root SDK readmes ([723e616](https://github.com/writer/writer-node/commit/723e616cc53d9a26740f5de5b72a1ec9e0313949)) +* update http mcp docs ([34a1c2e](https://github.com/writer/writer-node/commit/34a1c2e84ada77d9b1d6aa3b94edcc9ebebc9244)) + + +### Refactors + +* **tests:** switch from prism to steady ([5d62789](https://github.com/writer/writer-node/commit/5d6278939d566e78b574a04a11fc53659b29f5e1)) + +## 3.0.0 (2026-06-02) + Full Changelog: [v3.0.0-rc.1...v3.0.0](https://github.com/writer/writer-node/compare/v3.0.0-rc.1...v3.0.0) ### Features