Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

F/bb sdk v1.0: Updating the BrowserBase SDK from v0.x to v1.x #1033

Merged
merged 19 commits into from
Jan 16, 2025

Conversation

Vedantsahai18
Copy link
Member

@Vedantsahai18 Vedantsahai18 commented Jan 9, 2025

PR Type

Enhancement, Bug fix


Description

  • Updated the BrowserBase SDK integration to v1.0.

  • Refactored session handling methods for improved clarity.

  • Enhanced error handling in session and extension operations.

  • Updated dependencies to use the latest BrowserBase SDK version.


Changes walkthrough 📝

Relevant files
Enhancement
browserbase.py
Update models to align with BrowserBase SDK v1.0                 

integrations-service/integrations/models/browserbase.py

  • Updated imports to reflect new BrowserBase SDK structure.
  • Added connectionUrl field to BrowserbaseCreateSessionOutput.
  • Replaced DebugConnectionURLs with SessionLiveURLs.
  • +4/-2     
    browserbase.py
    Refactor and enhance BrowserBase integration utilities     

    integrations-service/integrations/utils/integrations/browserbase.py

  • Refactored session creation and retrieval methods.
  • Improved error handling for session and extension operations.
  • Updated API calls to match new SDK methods and parameters.
  • Enhanced temporary file handling for extension uploads.
  • +125/-71
    Dependencies
    pyproject.toml
    Update BrowserBase SDK dependency version                               

    integrations-service/pyproject.toml

    • Updated browserbase dependency to version >=1.0.5.
    +1/-1     

    💡 PR-Agent usage: Comment /help "your question" on any pull request to receive relevant information


    Important

    Update BrowserBase SDK to v1.0, refactor session handling, and remove deprecated connection URL methods.

    • SDK Update:
      • Updated BrowserBase SDK to v1.0 in pyproject.toml.
      • Removed deprecated BrowserbaseGetSessionConnectUrlArguments and related classes in Tools.py and browserbase.py.
    • Session Handling:
      • Refactored session creation and retrieval in browserbase.py.
      • Enhanced error handling for session and extension operations.
      • Updated API calls to match new SDK methods.
    • Miscellaneous:
      • Added platforms to docker-compose.yml for linux/amd64.
      • Updated connectionUrl field in BrowserbaseCreateSessionOutput and BrowserbaseGetSessionOutput.

    This description was created by Ellipsis for 666f5a6. It will automatically update as commits are pushed.

    Copy link

    gitguardian bot commented Jan 9, 2025

    ⚠️ GitGuardian has uncovered 1 secret following the scan of your pull request.

    Please consider investigating the findings and remediating the incidents. Failure to do so may lead to compromising the associated services or software components.

    🔎 Detected hardcoded secret in your pull request
    GitGuardian id GitGuardian status Secret Commit Filename
    14144715 Triggered Generic Password 253c732 deploy/simple-docker-compose.yaml View secret
    🛠 Guidelines to remediate hardcoded secrets
    1. Understand the implications of revoking this secret by investigating where it is used in your code.
    2. Replace and store your secret safely. Learn here the best practices.
    3. Revoke and rotate this secret.
    4. If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.

    To avoid such incidents in the future consider


    🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.

    @Vedantsahai18 Vedantsahai18 linked an issue Jan 9, 2025 that may be closed by this pull request
    1 task
    Copy link
    Contributor

    qodo-merge-pro-for-open-source bot commented Jan 9, 2025

    CI Failure Feedback 🧐

    (Checks updated until commit 9f7c363)

    Action: Test

    Failed stage: Run tests [❌]

    Failed test name: test_agent_routes

    Failure summary:

    The action failed due to a database connection pool configuration error. Specifically, the min_size
    (10) was set larger than the max_size (4) in the asyncpg connection pool initialization, which is
    invalid. This caused the database connection to fail during test startup, preventing the test
    fixtures from being properly initialized.

    The error affected multiple test cases in test_agent_routes.py:

  • route: unauthorized should fail
  • route: create agent
  • route: create agent with instructions

    All these tests failed with "Unable to resolve fixture 'client'" because the test client could not
    be created due to the invalid database pool configuration.

  • Relevant error logs:
    1:  ##[group]Operating System
    2:  Ubuntu
    ...
    
    1327:  PASS  test_agent_queries:28 query: create agent sql                          1%
    1328:  PASS  test_agent_queries:44 query: create or update agent sql                2%
    1329:  PASS  test_agent_queries:63 query: update agent sql                          2%
    1330:  PASS  test_agent_queries:85 query: get agent not exists sql                  3%
    1331:  PASS  test_agent_queries:96 query: get agent exists sql                      3%
    1332:  PASS  test_agent_queries:111 query: list agents sql                          4%
    1333:  PASS  test_agent_queries:122 query: patch agent sql                          4%
    1334:  PASS  test_agent_queries:143 query: delete agent sql                         5%
    1335:  FAIL  test_agent_routes:9 route: unauthorized should fail                    5%
    1336:  FAIL  test_agent_routes:26 route: create agent                               6%
    1337:  FAIL  test_agent_routes:43 route: create agent with instructions             7%
    1338:  ─────────────────────── route: unauthorized should fail ────────────────────────
    1339:  Failed at tests/test_agent_routes.py                                          
    ...
    
    1460:  │ │              name = '_dsn'                                           │ │  
    1461:  │ │              self = TestArgumentResolver(                            │ │  
    1462:  │ │                     │   test=Test(                                   │ │  
    1463:  │ │                     │   │   fn=<function _ at 0x7fe12fafb060>,       │ │  
    1464:  │ │                     │   │   module_name='test_agent_routes',         │ │  
    1465:  │ │                     │   │   id='c71c5f8b2acc4f35ad0eb52ab9d3504d',   │ │  
    1466:  │ │                     │   │   marker=None,                             │ │  
    1467:  │ │                     │   │   description='route: unauthorized should  │ │  
    1468:  │ │                     fail',                                           │ │  
    ...
    
    1587:  │ │ self = <anyio._backends._asyncio.BlockingPortal object at            │ │  
    1588:  │ │        0x7fe12f908b30>                                               │ │  
    1589:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    1590:  │                                                                          │  
    1591:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    1592:  │ python3.12/concurrent/futures/_base.py:456 in result                     │  
    1593:  │                                                                          │  
    1594:  │   453 │   │   │   │   if self._state in [CANCELLED, CANCELLED_AND_NOTIFI │  
    1595:  │   454 │   │   │   │   │   raise CancelledError()                         │  
    1596:  │   455 │   │   │   │   elif self._state == FINISHED:                      │  
    1597:  │ ❱ 456 │   │   │   │   │   return self.__get_result()                     │  
    1598:  │   457 │   │   │   │   else:                                              │  
    1599:  │   458 │   │   │   │   │   raise TimeoutError()                           │  
    ...
    
    1631:  │   221 │   │   except self._cancelled_exc_class:                          │  
    1632:  │                                                                          │  
    1633:  │ ╭─────────────────────────────── locals ───────────────────────────────╮ │  
    1634:  │ │                args = ()                                             │ │  
    1635:  │ │                func = <bound method TestClient.wait_startup of       │ │  
    1636:  │ │                       <starlette.testclient.TestClient object at     │ │  
    1637:  │ │                       0x7fe12f8e3500>>                               │ │  
    1638:  │ │              future = <Future at 0x7fe12f908ec0 state=finished       │ │  
    1639:  │ │                       raised ValueError>                             │ │  
    ...
    
    1643:  │ │               scope = None                                           │ │  
    1644:  │ │                self = <anyio._backends._asyncio.BlockingPortal       │ │  
    1645:  │ │                       object at 0x7fe12f908b30>                      │ │  
    1646:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    1647:  │                                                                          │  
    1648:  │ /home/runner/work/julep/julep/agents-api/.venv/lib/python3.12/site-packa │  
    1649:  │ ges/starlette/testclient.py:774 in wait_startup                          │  
    1650:  │                                                                          │  
    1651:  │   771 │   │   │   "lifespan.startup.failed",                             │  
    1652:  │   772 │   │   )                                                          │  
    1653:  │   773 │   │   if message["type"] == "lifespan.startup.failed":           │  
    1654:  │ ❱ 774 │   │   │   await receive()                                        │  
    1655:  │   775 │                                                                  │  
    1656:  │   776 │   async def wait_shutdown(self) -> None:                         │  
    1657:  │   777 │   │   async def receive() -> typing.Any:                         │  
    1658:  │                                                                          │  
    1659:  │ ╭─────────────────────────────── locals ───────────────────────────────╮ │  
    1660:  │ │ message = {                                                          │ │  
    1661:  │ │           │   'type': 'lifespan.startup.failed',                     │ │  
    ...
    
    1680:  │ │ message = None                                                       │ │  
    1681:  │ │    self = <starlette.testclient.TestClient object at 0x7fe12f8e3500> │ │  
    1682:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    1683:  │                                                                          │  
    1684:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    1685:  │ python3.12/concurrent/futures/_base.py:449 in result                     │  
    1686:  │                                                                          │  
    1687:  │   446 │   │   │   │   if self._state in [CANCELLED, CANCELLED_AND_NOTIFI │  
    1688:  │   447 │   │   │   │   │   raise CancelledError()                         │  
    ...
    
    1724:  │   221 │   │   except self._cancelled_exc_class:                          │  
    1725:  │                                                                          │  
    1726:  │ ╭─────────────────────────────── locals ───────────────────────────────╮ │  
    1727:  │ │                args = ()                                             │ │  
    1728:  │ │                func = <bound method TestClient.lifespan of           │ │  
    1729:  │ │                       <starlette.testclient.TestClient object at     │ │  
    1730:  │ │                       0x7fe12f8e3500>>                               │ │  
    1731:  │ │              future = <Future at 0x7fe12f9b6270 state=finished       │ │  
    1732:  │ │                       raised ValueError>                             │ │  
    ...
    
    1839:  │ │           waiting_senders=OrderedDict()), _closed=False),            │ │  
    1840:  │ │           receive_stream=MemoryObjectReceiveStream(_state=MemoryObj… │ │  
    1841:  │ │           buffer=deque([]), open_send_channels=1,                    │ │  
    1842:  │ │           open_receive_channels=1, waiting_receivers=OrderedDict(),  │ │  
    1843:  │ │           waiting_senders=OrderedDict()), _closed=False))>           │ │  
    1844:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    1845:  │                                                                          │  
    1846:  │ /home/runner/work/julep/julep/agents-api/.venv/lib/python3.12/site-packa │  
    1847:  │ ges/starlette/middleware/errors.py:152 in __call__                       │  
    ...
    
    1867:  │ │   scope = {                                                          │ │  
    1868:  │ │           │   'type': 'lifespan',                                    │ │  
    1869:  │ │           │   'state': {},                                           │ │  
    1870:  │ │           │   'app': <fastapi.applications.FastAPI object at         │ │  
    1871:  │ │           0x7fe13138ba40>,                                           │ │  
    1872:  │ │           │   'router': <fastapi.routing.APIRouter object at         │ │  
    1873:  │ │           0x7fe13cb276b0>                                            │ │  
    1874:  │ │           }                                                          │ │  
    1875:  │ │    self = <starlette.middleware.errors.ServerErrorMiddleware object  │ │  
    ...
    
    2097:  │ ges/starlette/routing.py:693 in lifespan                                 │  
    2098:  │                                                                          │  
    2099:  │   690 │   │   app: typing.Any = scope.get("app")                         │  
    2100:  │   691 │   │   await receive()                                            │  
    2101:  │   692 │   │   try:                                                       │  
    2102:  │ ❱ 693 │   │   │   async with self.lifespan_context(app) as maybe_state:  │  
    2103:  │   694 │   │   │   │   if maybe_state is not None:                        │  
    2104:  │   695 │   │   │   │   │   if "state" not in scope:                       │  
    2105:  │   696 │   │   │   │   │   │   raise RuntimeError('The server does not su │  
    ...
    
    2141:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    2142:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    2143:  │                                                                          │  
    2144:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    2145:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    2146:  │   209 │   │   try:                                                       │  
    2147:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    2148:  │   211 │   │   except StopAsyncIteration:                                 │  
    2149:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    2175:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    2176:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    2177:  │                                                                          │  
    2178:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    2179:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    2180:  │   209 │   │   try:                                                       │  
    2181:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    2182:  │   211 │   │   except StopAsyncIteration:                                 │  
    2183:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    2209:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    2210:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    2211:  │                                                                          │  
    2212:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    2213:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    2214:  │   209 │   │   try:                                                       │  
    2215:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    2216:  │   211 │   │   except StopAsyncIteration:                                 │  
    2217:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    2243:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    2244:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    2245:  │                                                                          │  
    2246:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    2247:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    2248:  │   209 │   │   try:                                                       │  
    2249:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    2250:  │   211 │   │   except StopAsyncIteration:                                 │  
    2251:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    2277:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    2278:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    2279:  │                                                                          │  
    2280:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    2281:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    2282:  │   209 │   │   try:                                                       │  
    2283:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    2284:  │   211 │   │   except StopAsyncIteration:                                 │  
    2285:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    2311:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    2312:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    2313:  │                                                                          │  
    2314:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    2315:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    2316:  │   209 │   │   try:                                                       │  
    2317:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    2318:  │   211 │   │   except StopAsyncIteration:                                 │  
    2319:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    2345:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    2346:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    2347:  │                                                                          │  
    2348:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    2349:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    2350:  │   209 │   │   try:                                                       │  
    2351:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    2352:  │   211 │   │   except StopAsyncIteration:                                 │  
    2353:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    2379:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    2380:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    2381:  │                                                                          │  
    2382:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    2383:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    2384:  │   209 │   │   try:                                                       │  
    2385:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    2386:  │   211 │   │   except StopAsyncIteration:                                 │  
    2387:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    2413:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    2414:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    2415:  │                                                                          │  
    2416:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    2417:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    2418:  │   209 │   │   try:                                                       │  
    2419:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    2420:  │   211 │   │   except StopAsyncIteration:                                 │  
    2421:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    2447:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    2448:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    2449:  │                                                                          │  
    2450:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    2451:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    2452:  │   209 │   │   try:                                                       │  
    2453:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    2454:  │   211 │   │   except StopAsyncIteration:                                 │  
    2455:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    2481:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    2482:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    2483:  │                                                                          │  
    2484:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    2485:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    2486:  │   209 │   │   try:                                                       │  
    2487:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    2488:  │   211 │   │   except StopAsyncIteration:                                 │  
    2489:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    2552:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    2553:  │                                                                          │  
    2554:  │ /home/runner/work/julep/julep/agents-api/.venv/lib/python3.12/site-packa │  
    2555:  │ ges/asyncpg/pool.py:361 in __init__                                      │  
    2556:  │                                                                          │  
    2557:  │    358 │   │   │   │   'min_size is expected to be greater or equal to z │  
    2558:  │    359 │   │                                                             │  
    2559:  │    360 │   │   if min_size > max_size:                                   │  
    2560:  │ ❱  361 │   │   │   raise ValueError('min_size is greater than max_size') │  
    2561:  │    362 │   │                                                             │  
    2562:  │    363 │   │   if max_queries <= 0:                                      │  
    2563:  │    364 │   │   │   raise ValueError('max_queries is expected to be great │  
    ...
    
    2577:  │ │                        max_size = 4                                  │ │  
    2578:  │ │                        min_size = 10                                 │ │  
    2579:  │ │                           reset = None                               │ │  
    2580:  │ │                            self = <asyncpg.pool.Pool object at       │ │  
    2581:  │ │                                   0x7fe12f881240>                    │ │  
    2582:  │ │                           setup = None                               │ │  
    2583:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    2584:  ╰──────────────────────────────────────────────────────────────────────────╯  
    2585:  ValueError: min_size is greater than max_size                                 
    ...
    
    2662:  │ │         │   }                                                        │ │  
    2663:  │ │         )                                                            │ │  
    2664:  │ │  self = TestArgumentResolver(                                        │ │  
    2665:  │ │         │   test=Test(                                               │ │  
    2666:  │ │         │   │   fn=<function _ at 0x7fe12fafb060>,                   │ │  
    2667:  │ │         │   │   module_name='test_agent_routes',                     │ │  
    2668:  │ │         │   │   id='c71c5f8b2acc4f35ad0eb52ab9d3504d',               │ │  
    2669:  │ │         │   │   marker=None,                                         │ │  
    2670:  │ │         │   │   description='route: unauthorized should fail',       │ │  
    ...
    
    2789:  │ │      resolved_args = {}                                              │ │  
    2790:  │ │               self = TestArgumentResolver(                           │ │  
    2791:  │ │                      │   test=Test(                                  │ │  
    2792:  │ │                      │   │   fn=<function _ at 0x7fe12fafb060>,      │ │  
    2793:  │ │                      │   │   module_name='test_agent_routes',        │ │  
    2794:  │ │                      │   │   id='c71c5f8b2acc4f35ad0eb52ab9d3504d',  │ │  
    2795:  │ │                      │   │   marker=None,                            │ │  
    2796:  │ │                      │   │   description='route: unauthorized should │ │  
    2797:  │ │                      fail',                                          │ │  
    ...
    
    2822:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    2823:  │                                                                          │  
    2824:  │ /home/runner/work/julep/julep/agents-api/.venv/lib/python3.12/site-packa │  
    2825:  │ ges/ward/testing.py:637 in _resolve_single_arg                           │  
    2826:  │                                                                          │  
    2827:  │   634 │   │   │   else:                                                  │  
    2828:  │   635 │   │   │   │   fixture.resolved_val = arg(**args_to_inject)       │  
    2829:  │   636 │   │   except (Exception, SystemExit) as e:                       │  
    2830:  │ ❱ 637 │   │   │   raise FixtureError(f"Unable to resolve fixture '{fixtu │  
    ...
    
    2943:  │ │              name = '_dsn'                                           │ │  
    2944:  │ │              self = TestArgumentResolver(                            │ │  
    2945:  │ │                     │   test=Test(                                   │ │  
    2946:  │ │                     │   │   fn=<function _ at 0x7fe12fafb060>,       │ │  
    2947:  │ │                     │   │   module_name='test_agent_routes',         │ │  
    2948:  │ │                     │   │   id='c71c5f8b2acc4f35ad0eb52ab9d3504d',   │ │  
    2949:  │ │                     │   │   marker=None,                             │ │  
    2950:  │ │                     │   │   description='route: unauthorized should  │ │  
    2951:  │ │                     fail',                                           │ │  
    ...
    
    2970:  │ │                     │   │   timer=<ward._testing._Timer object at    │ │  
    2971:  │ │                     0x7fe12f8b7260>,                                 │ │  
    2972:  │ │                     │   │   tags=[]                                  │ │  
    2973:  │ │                     │   ),                                           │ │  
    2974:  │ │                     │   iteration=0                                  │ │  
    2975:  │ │                     )                                                │ │  
    2976:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    2977:  ╰──────────────────────────────────────────────────────────────────────────╯  
    2978:  FixtureError: Unable to resolve fixture 'client'                              
    2979:  ───────────────────────────── route: create agent ──────────────────────────────
    2980:  Failed at tests/test_agent_routes.py                                          
    ...
    
    3227:  │ │ self = <anyio._backends._asyncio.BlockingPortal object at            │ │  
    3228:  │ │        0x7fe12f90ac00>                                               │ │  
    3229:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    3230:  │                                                                          │  
    3231:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    3232:  │ python3.12/concurrent/futures/_base.py:456 in result                     │  
    3233:  │                                                                          │  
    3234:  │   453 │   │   │   │   if self._state in [CANCELLED, CANCELLED_AND_NOTIFI │  
    3235:  │   454 │   │   │   │   │   raise CancelledError()                         │  
    3236:  │   455 │   │   │   │   elif self._state == FINISHED:                      │  
    3237:  │ ❱ 456 │   │   │   │   │   return self.__get_result()                     │  
    3238:  │   457 │   │   │   │   else:                                              │  
    3239:  │   458 │   │   │   │   │   raise TimeoutError()                           │  
    ...
    
    3271:  │   221 │   │   except self._cancelled_exc_class:                          │  
    3272:  │                                                                          │  
    3273:  │ ╭─────────────────────────────── locals ───────────────────────────────╮ │  
    3274:  │ │                args = ()                                             │ │  
    3275:  │ │                func = <bound method TestClient.wait_startup of       │ │  
    3276:  │ │                       <starlette.testclient.TestClient object at     │ │  
    3277:  │ │                       0x7fe12f90a870>>                               │ │  
    3278:  │ │              future = <Future at 0x7fe12f90afc0 state=finished       │ │  
    3279:  │ │                       raised ValueError>                             │ │  
    ...
    
    3283:  │ │               scope = None                                           │ │  
    3284:  │ │                self = <anyio._backends._asyncio.BlockingPortal       │ │  
    3285:  │ │                       object at 0x7fe12f90ac00>                      │ │  
    3286:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    3287:  │                                                                          │  
    3288:  │ /home/runner/work/julep/julep/agents-api/.venv/lib/python3.12/site-packa │  
    3289:  │ ges/starlette/testclient.py:774 in wait_startup                          │  
    3290:  │                                                                          │  
    3291:  │   771 │   │   │   "lifespan.startup.failed",                             │  
    3292:  │   772 │   │   )                                                          │  
    3293:  │   773 │   │   if message["type"] == "lifespan.startup.failed":           │  
    3294:  │ ❱ 774 │   │   │   await receive()                                        │  
    3295:  │   775 │                                                                  │  
    3296:  │   776 │   async def wait_shutdown(self) -> None:                         │  
    3297:  │   777 │   │   async def receive() -> typing.Any:                         │  
    3298:  │                                                                          │  
    3299:  │ ╭─────────────────────────────── locals ───────────────────────────────╮ │  
    3300:  │ │ message = {                                                          │ │  
    3301:  │ │           │   'type': 'lifespan.startup.failed',                     │ │  
    ...
    
    3320:  │ │ message = None                                                       │ │  
    3321:  │ │    self = <starlette.testclient.TestClient object at 0x7fe12f90a870> │ │  
    3322:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    3323:  │                                                                          │  
    3324:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    3325:  │ python3.12/concurrent/futures/_base.py:449 in result                     │  
    3326:  │                                                                          │  
    3327:  │   446 │   │   │   │   if self._state in [CANCELLED, CANCELLED_AND_NOTIFI │  
    3328:  │   447 │   │   │   │   │   raise CancelledError()                         │  
    ...
    
    3364:  │   221 │   │   except self._cancelled_exc_class:                          │  
    3365:  │                                                                          │  
    3366:  │ ╭─────────────────────────────── locals ───────────────────────────────╮ │  
    3367:  │ │                args = ()                                             │ │  
    3368:  │ │                func = <bound method TestClient.lifespan of           │ │  
    3369:  │ │                       <starlette.testclient.TestClient object at     │ │  
    3370:  │ │                       0x7fe12f90a870>>                               │ │  
    3371:  │ │              future = <Future at 0x7fe12f90af00 state=finished       │ │  
    3372:  │ │                       raised ValueError>                             │ │  
    ...
    
    3479:  │ │           waiting_senders=OrderedDict()), _closed=False),            │ │  
    3480:  │ │           receive_stream=MemoryObjectReceiveStream(_state=MemoryObj… │ │  
    3481:  │ │           buffer=deque([]), open_send_channels=1,                    │ │  
    3482:  │ │           open_receive_channels=1, waiting_receivers=OrderedDict(),  │ │  
    3483:  │ │           waiting_senders=OrderedDict()), _closed=False))>           │ │  
    3484:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    3485:  │                                                                          │  
    3486:  │ /home/runner/work/julep/julep/agents-api/.venv/lib/python3.12/site-packa │  
    3487:  │ ges/starlette/middleware/errors.py:152 in __call__                       │  
    ...
    
    3507:  │ │   scope = {                                                          │ │  
    3508:  │ │           │   'type': 'lifespan',                                    │ │  
    3509:  │ │           │   'state': {},                                           │ │  
    3510:  │ │           │   'app': <fastapi.applications.FastAPI object at         │ │  
    3511:  │ │           0x7fe13138ba40>,                                           │ │  
    3512:  │ │           │   'router': <fastapi.routing.APIRouter object at         │ │  
    3513:  │ │           0x7fe13cb276b0>                                            │ │  
    3514:  │ │           }                                                          │ │  
    3515:  │ │    self = <starlette.middleware.errors.ServerErrorMiddleware object  │ │  
    ...
    
    3737:  │ ges/starlette/routing.py:693 in lifespan                                 │  
    3738:  │                                                                          │  
    3739:  │   690 │   │   app: typing.Any = scope.get("app")                         │  
    3740:  │   691 │   │   await receive()                                            │  
    3741:  │   692 │   │   try:                                                       │  
    3742:  │ ❱ 693 │   │   │   async with self.lifespan_context(app) as maybe_state:  │  
    3743:  │   694 │   │   │   │   if maybe_state is not None:                        │  
    3744:  │   695 │   │   │   │   │   if "state" not in scope:                       │  
    3745:  │   696 │   │   │   │   │   │   raise RuntimeError('The server does not su │  
    ...
    
    3781:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    3782:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    3783:  │                                                                          │  
    3784:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    3785:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    3786:  │   209 │   │   try:                                                       │  
    3787:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    3788:  │   211 │   │   except StopAsyncIteration:                                 │  
    3789:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    3815:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    3816:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    3817:  │                                                                          │  
    3818:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    3819:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    3820:  │   209 │   │   try:                                                       │  
    3821:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    3822:  │   211 │   │   except StopAsyncIteration:                                 │  
    3823:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    3849:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    3850:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    3851:  │                                                                          │  
    3852:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    3853:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    3854:  │   209 │   │   try:                                                       │  
    3855:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    3856:  │   211 │   │   except StopAsyncIteration:                                 │  
    3857:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    3883:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    3884:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    3885:  │                                                                          │  
    3886:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    3887:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    3888:  │   209 │   │   try:                                                       │  
    3889:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    3890:  │   211 │   │   except StopAsyncIteration:                                 │  
    3891:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    3917:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    3918:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    3919:  │                                                                          │  
    3920:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    3921:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    3922:  │   209 │   │   try:                                                       │  
    3923:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    3924:  │   211 │   │   except StopAsyncIteration:                                 │  
    3925:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    3951:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    3952:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    3953:  │                                                                          │  
    3954:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    3955:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    3956:  │   209 │   │   try:                                                       │  
    3957:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    3958:  │   211 │   │   except StopAsyncIteration:                                 │  
    3959:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    3985:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    3986:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    3987:  │                                                                          │  
    3988:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    3989:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    3990:  │   209 │   │   try:                                                       │  
    3991:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    3992:  │   211 │   │   except StopAsyncIteration:                                 │  
    3993:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    4019:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    4020:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    4021:  │                                                                          │  
    4022:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    4023:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    4024:  │   209 │   │   try:                                                       │  
    4025:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    4026:  │   211 │   │   except StopAsyncIteration:                                 │  
    4027:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    4053:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    4054:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    4055:  │                                                                          │  
    4056:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    4057:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    4058:  │   209 │   │   try:                                                       │  
    4059:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    4060:  │   211 │   │   except StopAsyncIteration:                                 │  
    4061:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    4087:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    4088:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    4089:  │                                                                          │  
    4090:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    4091:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    4092:  │   209 │   │   try:                                                       │  
    4093:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    4094:  │   211 │   │   except StopAsyncIteration:                                 │  
    4095:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    4121:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    4122:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    4123:  │                                                                          │  
    4124:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    4125:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    4126:  │   209 │   │   try:                                                       │  
    4127:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    4128:  │   211 │   │   except StopAsyncIteration:                                 │  
    4129:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    4192:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    4193:  │                                                                          │  
    4194:  │ /home/runner/work/julep/julep/agents-api/.venv/lib/python3.12/site-packa │  
    4195:  │ ges/asyncpg/pool.py:361 in __init__                                      │  
    4196:  │                                                                          │  
    4197:  │    358 │   │   │   │   'min_size is expected to be greater or equal to z │  
    4198:  │    359 │   │                                                             │  
    4199:  │    360 │   │   if min_size > max_size:                                   │  
    4200:  │ ❱  361 │   │   │   raise ValueError('min_size is greater than max_size') │  
    4201:  │    362 │   │                                                             │  
    4202:  │    363 │   │   if max_queries <= 0:                                      │  
    4203:  │    364 │   │   │   raise ValueError('max_queries is expected to be great │  
    ...
    
    4217:  │ │                        max_size = 4                                  │ │  
    4218:  │ │                        min_size = 10                                 │ │  
    4219:  │ │                           reset = None                               │ │  
    4220:  │ │                            self = <asyncpg.pool.Pool object at       │ │  
    4221:  │ │                                   0x7fe12f883d00>                    │ │  
    4222:  │ │                           setup = None                               │ │  
    4223:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    4224:  ╰──────────────────────────────────────────────────────────────────────────╯  
    4225:  ValueError: min_size is greater than max_size                                 
    ...
    
    4603:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    4604:  │                                                                          │  
    4605:  │ /home/runner/work/julep/julep/agents-api/.venv/lib/python3.12/site-packa │  
    4606:  │ ges/ward/testing.py:637 in _resolve_single_arg                           │  
    4607:  │                                                                          │  
    4608:  │   634 │   │   │   else:                                                  │  
    4609:  │   635 │   │   │   │   fixture.resolved_val = arg(**args_to_inject)       │  
    4610:  │   636 │   │   except (Exception, SystemExit) as e:                       │  
    4611:  │ ❱ 637 │   │   │   raise FixtureError(f"Unable to resolve fixture '{fixtu │  
    ...
    
    4750:  │ │                     │   │   timer=<ward._testing._Timer object at    │ │  
    4751:  │ │                     0x7fe12f9dcf20>,                                 │ │  
    4752:  │ │                     │   │   tags=[]                                  │ │  
    4753:  │ │                     │   ),                                           │ │  
    4754:  │ │                     │   iteration=0                                  │ │  
    4755:  │ │                     )                                                │ │  
    4756:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    4757:  ╰──────────────────────────────────────────────────────────────────────────╯  
    4758:  FixtureError: Unable to resolve fixture 'client'                              
    4759:  ──────────────────── route: create agent with instructions ─────────────────────
    4760:  Failed at tests/test_agent_routes.py                                          
    ...
    
    5008:  │ │ self = <anyio._backends._asyncio.BlockingPortal object at            │ │  
    5009:  │ │        0x7fe12f90be60>                                               │ │  
    5010:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    5011:  │                                                                          │  
    5012:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    5013:  │ python3.12/concurrent/futures/_base.py:456 in result                     │  
    5014:  │                                                                          │  
    5015:  │   453 │   │   │   │   if self._state in [CANCELLED, CANCELLED_AND_NOTIFI │  
    5016:  │   454 │   │   │   │   │   raise CancelledError()                         │  
    5017:  │   455 │   │   │   │   elif self._state == FINISHED:                      │  
    5018:  │ ❱ 456 │   │   │   │   │   return self.__get_result()                     │  
    5019:  │   457 │   │   │   │   else:                                              │  
    5020:  │   458 │   │   │   │   │   raise TimeoutError()                           │  
    ...
    
    5052:  │   221 │   │   except self._cancelled_exc_class:                          │  
    5053:  │                                                                          │  
    5054:  │ ╭─────────────────────────────── locals ───────────────────────────────╮ │  
    5055:  │ │                args = ()                                             │ │  
    5056:  │ │                func = <bound method TestClient.wait_startup of       │ │  
    5057:  │ │                       <starlette.testclient.TestClient object at     │ │  
    5058:  │ │                       0x7fe12f90b7d0>>                               │ │  
    5059:  │ │              future = <Future at 0x7fe12f90c260 state=finished       │ │  
    5060:  │ │                       raised ValueError>                             │ │  
    ...
    
    5064:  │ │               scope = None                                           │ │  
    5065:  │ │                self = <anyio._backends._asyncio.BlockingPortal       │ │  
    5066:  │ │                       object at 0x7fe12f90be60>                      │ │  
    5067:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    5068:  │                                                                          │  
    5069:  │ /home/runner/work/julep/julep/agents-api/.venv/lib/python3.12/site-packa │  
    5070:  │ ges/starlette/testclient.py:774 in wait_startup                          │  
    5071:  │                                                                          │  
    5072:  │   771 │   │   │   "lifespan.startup.failed",                             │  
    5073:  │   772 │   │   )                                                          │  
    5074:  │   773 │   │   if message["type"] == "lifespan.startup.failed":           │  
    5075:  │ ❱ 774 │   │   │   await receive()                                        │  
    5076:  │   775 │                                                                  │  
    5077:  │   776 │   async def wait_shutdown(self) -> None:                         │  
    5078:  │   777 │   │   async def receive() -> typing.Any:                         │  
    5079:  │                                                                          │  
    5080:  │ ╭─────────────────────────────── locals ───────────────────────────────╮ │  
    5081:  │ │ message = {                                                          │ │  
    5082:  │ │           │   'type': 'lifespan.startup.failed',                     │ │  
    ...
    
    5101:  │ │ message = None                                                       │ │  
    5102:  │ │    self = <starlette.testclient.TestClient object at 0x7fe12f90b7d0> │ │  
    5103:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    5104:  │                                                                          │  
    5105:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    5106:  │ python3.12/concurrent/futures/_base.py:449 in result                     │  
    5107:  │                                                                          │  
    5108:  │   446 │   │   │   │   if self._state in [CANCELLED, CANCELLED_AND_NOTIFI │  
    5109:  │   447 │   │   │   │   │   raise CancelledError()                         │  
    ...
    
    5145:  │   221 │   │   except self._cancelled_exc_class:                          │  
    5146:  │                                                                          │  
    5147:  │ ╭─────────────────────────────── locals ───────────────────────────────╮ │  
    5148:  │ │                args = ()                                             │ │  
    5149:  │ │                func = <bound method TestClient.lifespan of           │ │  
    5150:  │ │                       <starlette.testclient.TestClient object at     │ │  
    5151:  │ │                       0x7fe12f90b7d0>>                               │ │  
    5152:  │ │              future = <Future at 0x7fe12f90c1a0 state=finished       │ │  
    5153:  │ │                       raised ValueError>                             │ │  
    ...
    
    5260:  │ │           waiting_senders=OrderedDict()), _closed=False),            │ │  
    5261:  │ │           receive_stream=MemoryObjectReceiveStream(_state=MemoryObj… │ │  
    5262:  │ │           buffer=deque([]), open_send_channels=1,                    │ │  
    5263:  │ │           open_receive_channels=1, waiting_receivers=OrderedDict(),  │ │  
    5264:  │ │           waiting_senders=OrderedDict()), _closed=False))>           │ │  
    5265:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    5266:  │                                                                          │  
    5267:  │ /home/runner/work/julep/julep/agents-api/.venv/lib/python3.12/site-packa │  
    5268:  │ ges/starlette/middleware/errors.py:152 in __call__                       │  
    ...
    
    5288:  │ │   scope = {                                                          │ │  
    5289:  │ │           │   'type': 'lifespan',                                    │ │  
    5290:  │ │           │   'state': {},                                           │ │  
    5291:  │ │           │   'app': <fastapi.applications.FastAPI object at         │ │  
    5292:  │ │           0x7fe13138ba40>,                                           │ │  
    5293:  │ │           │   'router': <fastapi.routing.APIRouter object at         │ │  
    5294:  │ │           0x7fe13cb276b0>                                            │ │  
    5295:  │ │           }                                                          │ │  
    5296:  │ │    self = <starlette.middleware.errors.ServerErrorMiddleware object  │ │  
    ...
    
    5518:  │ ges/starlette/routing.py:693 in lifespan                                 │  
    5519:  │                                                                          │  
    5520:  │   690 │   │   app: typing.Any = scope.get("app")                         │  
    5521:  │   691 │   │   await receive()                                            │  
    5522:  │   692 │   │   try:                                                       │  
    5523:  │ ❱ 693 │   │   │   async with self.lifespan_context(app) as maybe_state:  │  
    5524:  │   694 │   │   │   │   if maybe_state is not None:                        │  
    5525:  │   695 │   │   │   │   │   if "state" not in scope:                       │  
    5526:  │   696 │   │   │   │   │   │   raise RuntimeError('The server does not su │  
    ...
    
    5562:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    5563:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    5564:  │                                                                          │  
    5565:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    5566:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    5567:  │   209 │   │   try:                                                       │  
    5568:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    5569:  │   211 │   │   except StopAsyncIteration:                                 │  
    5570:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    5596:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    5597:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    5598:  │                                                                          │  
    5599:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    5600:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    5601:  │   209 │   │   try:                                                       │  
    5602:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    5603:  │   211 │   │   except StopAsyncIteration:                                 │  
    5604:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    5630:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    5631:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    5632:  │                                                                          │  
    5633:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    5634:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    5635:  │   209 │   │   try:                                                       │  
    5636:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    5637:  │   211 │   │   except StopAsyncIteration:                                 │  
    5638:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    5664:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    5665:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    5666:  │                                                                          │  
    5667:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    5668:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    5669:  │   209 │   │   try:                                                       │  
    5670:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    5671:  │   211 │   │   except StopAsyncIteration:                                 │  
    5672:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    5698:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    5699:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    5700:  │                                                                          │  
    5701:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    5702:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    5703:  │   209 │   │   try:                                                       │  
    5704:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    5705:  │   211 │   │   except StopAsyncIteration:                                 │  
    5706:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    5732:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    5733:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    5734:  │                                                                          │  
    5735:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    5736:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    5737:  │   209 │   │   try:                                                       │  
    5738:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    5739:  │   211 │   │   except StopAsyncIteration:                                 │  
    5740:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    5766:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    5767:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    5768:  │                                                                          │  
    5769:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    5770:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    5771:  │   209 │   │   try:                                                       │  
    5772:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    5773:  │   211 │   │   except StopAsyncIteration:                                 │  
    5774:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    5800:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    5801:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    5802:  │                                                                          │  
    5803:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    5804:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    5805:  │   209 │   │   try:                                                       │  
    5806:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    5807:  │   211 │   │   except StopAsyncIteration:                                 │  
    5808:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    5834:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    5835:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    5836:  │                                                                          │  
    5837:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    5838:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    5839:  │   209 │   │   try:                                                       │  
    5840:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    5841:  │   211 │   │   except StopAsyncIteration:                                 │  
    5842:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    5868:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    5869:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    5870:  │                                                                          │  
    5871:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    5872:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    5873:  │   209 │   │   try:                                                       │  
    5874:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    5875:  │   211 │   │   except StopAsyncIteration:                                 │  
    5876:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    5902:  │ /home/runner/.local/share/uv/python/cpython-3.12.8-linux-x86_64-gnu/lib/ │  
    5903:  │ python3.12/contextlib.py:210 in __aenter__                               │  
    5904:  │                                                                          │  
    5905:  │   207 │   │   # they are only needed for recreation, which is not possib │  
    5906:  │   208 │   │   del self.args, self.kwds, self.func                        │  
    5907:  │   209 │   │   try:                                                       │  
    5908:  │ ❱ 210 │   │   │   return await anext(self.gen)                           │  
    5909:  │   211 │   │   except StopAsyncIteration:                                 │  
    5910:  │   212 │   │   │   raise RuntimeError("generator didn't yield") from None │  
    ...
    
    5973:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    5974:  │                                                                          │  
    5975:  │ /home/runner/work/julep/julep/agents-api/.venv/lib/python3.12/site-packa │  
    5976:  │ ges/asyncpg/pool.py:361 in __init__                                      │  
    5977:  │                                                                          │  
    5978:  │    358 │   │   │   │   'min_size is expected to be greater or equal to z │  
    5979:  │    359 │   │                                                             │  
    5980:  │    360 │   │   if min_size > max_size:                                   │  
    5981:  │ ❱  361 │   │   │   raise ValueError('min_size is greater than max_size') │  
    5982:  │    362 │   │                                                             │  
    5983:  │    363 │   │   if max_queries <= 0:                                      │  
    5984:  │    364 │   │   │   raise ValueError('max_queries is expected to be great │  
    ...
    
    5998:  │ │                        max_size = 4                                  │ │  
    5999:  │ │                        min_size = 10                                 │ │  
    6000:  │ │                           reset = None                               │ │  
    6001:  │ │                            self = <asyncpg.pool.Pool object at       │ │  
    6002:  │ │                                   0x7fe12e7b84c0>                    │ │  
    6003:  │ │                           setup = None                               │ │  
    6004:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    6005:  ╰──────────────────────────────────────────────────────────────────────────╯  
    6006:  ValueError: min_size is greater than max_size                                 
    ...
    
    6386:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    6387:  │                                                                          │  
    6388:  │ /home/runner/work/julep/julep/agents-api/.venv/lib/python3.12/site-packa │  
    6389:  │ ges/ward/testing.py:637 in _resolve_single_arg                           │  
    6390:  │                                                                          │  
    6391:  │   634 │   │   │   else:                                                  │  
    6392:  │   635 │   │   │   │   fixture.resolved_val = arg(**args_to_inject)       │  
    6393:  │   636 │   │   except (Exception, SystemExit) as e:                       │  
    6394:  │ ❱ 637 │   │   │   raise FixtureError(f"Unable to resolve fixture '{fixtu │  
    ...
    
    6534:  │ │                     │   │   timer=<ward._testing._Timer object at    │ │  
    6535:  │ │                     0x7fe12f864c80>,                                 │ │  
    6536:  │ │                     │   │   tags=[]                                  │ │  
    6537:  │ │                     │   ),                                           │ │  
    6538:  │ │                     │   iteration=0                                  │ │  
    6539:  │ │                     )                                                │ │  
    6540:  │ ╰──────────────────────────────────────────────────────────────────────╯ │  
    6541:  ╰──────────────────────────────────────────────────────────────────────────╯  
    6542:  FixtureError: Unable to resolve fixture 'client'                              
    6543:  ────────────────────────────────────────────────────────────────────────────────
    6544:  ╭──────────── Results ─────────────╮
    6545:  │  12  Tests Encountered           │
    6546:  │   9  Passes             (75.0%)  │
    6547:  │   3  Failures           (25.0%)  │
    6548:  ╰──────────────────────────────────╯
    6549:  ─────────────────────────── FAILED in 60.10 seconds ────────────────────────────
    6550:  ##[error]Process completed with exit code 1.
    

    ✨ CI feedback usage guide:

    The CI feedback tool (/checks) automatically triggers when a PR has a failed check.
    The tool analyzes the failed checks and provides several feedbacks:

    • Failed stage
    • Failed test name
    • Failure summary
    • Relevant error logs

    In addition to being automatically triggered, the tool can also be invoked manually by commenting on a PR:

    /checks "https://github.com/{repo_name}/actions/runs/{run_number}/job/...
    

    @Vedantsahai18 Vedantsahai18 marked this pull request as ready for review January 15, 2025 01:54
    Copy link
    Contributor

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 4 🔵🔵🔵🔵⚪
    🧪 No relevant tests
    🔒 Security concerns

    API Key Exposure:
    The code includes API key handling in headers and URLs. While the API key is not directly exposed, the error handling in the extension installation function could potentially log sensitive information including the API key in error messages. Consider implementing proper error redaction before logging.

    ⚡ Recommended focus areas for review

    Typo Bug

    There appears to be a typo in the session connection URL field name which could cause connection issues. The field is written as 'connectionslqUrl' instead of 'connectionUrl'

    connectionslqUrl=session.connect_url,
    Hardcoded URL

    The connect URL is hardcoded with a fixed WebSocket URL pattern. This could be problematic if the service endpoint changes or if different environments require different URLs

    f"wss://connect.browserbase.com?sessionId={arguments.id}&apiKey={setup.api_key}"
    Error Handling

    The extension installation function catches and logs errors but then re-raises them, which might expose sensitive information in the logs while not providing meaningful error handling

    except httpx.HTTPError as e:
        print(f"Error downloading extension from GitHub: {e}")
        raise

    Copy link
    Contributor

    qodo-merge-pro-for-open-source bot commented Jan 15, 2025

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Score
    Possible issue
    ✅ Fix a critical typo in field name that prevents proper connection URL assignment
    Suggestion Impact:The commit fixed the typo in the field name exactly as suggested, changing 'connectionslqUrl' to 'connectionUrl'

    code diff:

    -        connectionslqUrl=session.connect_url,
    +        connectionUrl=session.connect_url,

    Fix the typo in the 'connectionUrl' field assignment during session creation. The
    current code uses 'connectionslqUrl' which is incorrect and will cause the
    connection URL to be missing in the output.

    integrations-service/integrations/utils/integrations/browserbase.py [105-109]

     return BrowserbaseCreateSessionOutput(
         id=session.id,
    -    connectionslqUrl=session.connect_url,
    +    connectionUrl=session.connect_url,
         createdAt=session.created_at.isoformat() if session.created_at else None,
     )
    • Apply this suggestion
    Suggestion importance[1-10]: 9

    Why: The typo 'connectionslqUrl' instead of 'connectionUrl' is a critical bug that would prevent the connection URL from being properly set in the output, breaking client functionality.

    9
    Security
    ✅ Replace hardcoded WebSocket URL with proper SDK method call to ensure reliability
    Suggestion Impact:The commit removed the get_connect_url function that contained the hardcoded WebSocket URL, and instead appears to be using the connect_url from the session object directly (as seen in line 22)

    code diff:

    -async def get_connect_url(
    -    setup: BrowserbaseSetup, arguments: BrowserbaseGetSessionConnectUrlArguments
    -) -> BrowserbaseGetSessionConnectUrlOutput:
    -    """Get the connect URL for a session."""
    -    # TODO: Get a better way to get the connect URL than this
    -    try:
    -        # Get session to access its connect_url
    -        CONNECT_URL = (
    -            f"wss://connect.browserbase.com?sessionId={arguments.id}&apiKey={setup.api_key}"
    -        )
    -        return BrowserbaseGetSessionConnectUrlOutput(url=CONNECT_URL)
    -    except Exception as e:
    -        print(f"Error getting connect URL: {e}")
    -        raise
    -

    The hardcoded WebSocket URL in get_connect_url() is unsafe and inflexible. Instead,
    use the SDK's built-in methods or configuration to get the proper connect URL, as
    the hardcoded URL might break if the service endpoint changes.

    integrations-service/integrations/utils/integrations/browserbase.py [207-209]

    -CONNECT_URL = (
    -    f"wss://connect.browserbase.com?sessionId={arguments.id}&apiKey={setup.api_key}"
    -)
    -return BrowserbaseGetSessionConnectUrlOutput(url=CONNECT_URL)
    +session = client.sessions.retrieve(id=arguments.id)
    +if not session.connect_url:
    +    raise ValueError("No connect URL available for this session")
    +return BrowserbaseGetSessionConnectUrlOutput(url=session.connect_url)
    • Apply this suggestion
    Suggestion importance[1-10]: 8

    Why: Hardcoding the WebSocket URL is risky as it could break if the service endpoint changes. Using the SDK's built-in methods would make the code more maintainable and reliable.

    8
    General
    ✅ Improve error handling structure to prevent error masking and provide better error context

    The error handling in install_extension_from_github() has nested try-except blocks
    that might mask important errors. Consolidate error handling and add specific
    exception types instead of catching all exceptions.

    integrations-service/integrations/utils/integrations/browserbase.py [226-236]

    -try:
    -    github_url = f"https://github.com/{arguments.repository_name}/archive/refs/tags/{arguments.ref}.zip"
    -    async with httpx.AsyncClient(timeout=600) as client:
    -        try:
    -            response = await client.get(github_url, follow_redirects=True)
    -            response.raise_for_status()
    -        except httpx.HTTPError as e:
    -            print(f"Error downloading extension from GitHub: {e}")
    -            raise
    +async with httpx.AsyncClient(timeout=600) as client:
    +    try:
    +        response = await client.get(github_url, follow_redirects=True)
    +        response.raise_for_status()
    +    except httpx.HTTPError as e:
    +        raise ValueError(f"Failed to download extension: {e}") from e
    +    except Exception as e:
    +        raise RuntimeError(f"Unexpected error downloading extension: {e}") from e

    [Suggestion has been applied]

    Suggestion importance[1-10]: 5

    Why: While the current error handling works, the suggested restructuring would provide clearer error context and prevent potential error masking, improving debugging capabilities.

    5

    Copy link
    Contributor

    @ellipsis-dev ellipsis-dev bot left a comment

    Choose a reason for hiding this comment

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

    ❌ Changes requested. Reviewed everything up to b033fb4 in 1 minute and 2 seconds

    More details
    • Looked at 365 lines of code in 4 files
    • Skipped 0 files when reviewing.
    • Skipped posting 1 drafted comments based on config settings.
    1. integrations-service/uv.lock:229
    • Draft comment:
      Use 'sys_platform' instead of 'platform_system' for consistency.
        { name = "colorama", marker = "sys_platform == 'win32'" },
    
    • Reason this comment was not posted:
      Confidence changes required: 50%
      The code is using 'platform_system' instead of 'sys_platform' in the marker for 'colorama'. This should be consistent with the other changes in the lock file.

    Workflow ID: wflow_H77qeuBHPO1bmrlC


    Want Ellipsis to fix these issues? Tag @ellipsis-dev in a comment. You can customize Ellipsis with 👍 / 👎 feedback, review rules, user-specific overrides, quiet mode, and more.

    …se.py
    
    Co-authored-by: ellipsis-dev[bot] <65095814+ellipsis-dev[bot]@users.noreply.github.com>
    Copy link
    Contributor

    @ellipsis-dev ellipsis-dev bot left a comment

    Choose a reason for hiding this comment

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

    👍 Looks good to me! Incremental review on 4498579 in 30 seconds

    More details
    • Looked at 484 lines of code in 9 files
    • Skipped 0 files when reviewing.
    • Skipped posting 1 drafted comments based on config settings.
    1. integrations-service/integrations/models/browserbase.py:16
    • Draft comment:
      The field name connectionUrl should be consistently updated to connect_url to follow Python naming conventions. This change should be reflected wherever this field is used.
    • Reason this comment was not posted:
      Comment looked like it was already resolved.

    Workflow ID: wflow_alMqZVg7DjRgnzuP


    You can customize Ellipsis with 👍 / 👎 feedback, review rules, user-specific overrides, quiet mode, and more.

    Copy link
    Contributor

    @ellipsis-dev ellipsis-dev bot left a comment

    Choose a reason for hiding this comment

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

    👍 Looks good to me! Incremental review on 666f5a6 in 15 seconds

    More details
    • Looked at 22 lines of code in 1 files
    • Skipped 0 files when reviewing.
    • Skipped posting 1 drafted comments based on config settings.
    1. agents-api/docker-compose.yml:54
    • Draft comment:
      Consider verifying if specifying the platform is necessary for all services or just specific ones. This can help avoid unnecessary constraints.
    • Reason this comment was not posted:
      Confidence changes required: 50%
      The addition of the 'platforms' key in the docker-compose.yml file is a good practice for ensuring compatibility with specific architectures. However, it should be verified if this is necessary for all services or just specific ones.

    Workflow ID: wflow_KRuBLXkufgEkaUIv


    You can customize Ellipsis with 👍 / 👎 feedback, review rules, user-specific overrides, quiet mode, and more.

    Copy link
    Contributor

    @ellipsis-dev ellipsis-dev bot left a comment

    Choose a reason for hiding this comment

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

    Skipped PR review on de652e3 because no changed files had a supported extension. If you think this was in error, please contact us and we'll fix it right away.

    @Ahmad-mtos Ahmad-mtos merged commit 4085297 into dev Jan 16, 2025
    13 of 17 checks passed
    @Ahmad-mtos Ahmad-mtos deleted the f/bb-sdk-v1.0 branch January 16, 2025 06:52
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    [Bug]: (intgrations) Upgrade from browserbase==0.3 to browserbase>=1.0
    2 participants