Skip to content
This repository was archived by the owner on Jun 5, 2025. It is now read-only.
This repository was archived by the owner on Jun 5, 2025. It is now read-only.

Investigate shareable workspaces #1067

Description

@lukehinds

Investigate a simple shareable workspace configuration, where a user could export a workspace, capturing prompts , provider config and muxing rules. This could be saved as file which someone else could then import.

Activity

  1. JAORMX commented on Feb 15, 2025

    @JAORMX
    Contributor

    I could look at this. Provider config is not workspace-scoped, but I'm sure we could make it work

  2. peppescg commented on Feb 17, 2025

    @peppescg
    Contributor

    I think this will impact the UI dashboard too. Cause I would expect to have a button in the dashboard and import/export the config ( keep in mind that muxing is actually available only in UI).

  3. JAORMX commented on Feb 17, 2025

    @JAORMX
    Contributor

    We agreed someone else will work on this. I can tag along and help out if needed.

  4. JAORMX commented on Feb 17, 2025

    @JAORMX
    Contributor

    I'll pair up with @alex-mcgovern

  5. lxmcgvrn commented on Feb 19, 2025

    @lxmcgvrn
    Contributor

    Actually picking this up now

  6. JAORMX commented on Feb 19, 2025

    @JAORMX
    Contributor

    #1086 added the basic configuration. It's hooked to the workspace creation REST API endpoint, but currently unused. I can see us parsing a JSON file with that content too as an alternative.

  7. lxmcgvrn commented on Feb 19, 2025

    @lxmcgvrn
    Contributor

    I think a north star for this should be a local JSON "CodeGate config", this would allow:

    • hand editing in editor-of-choice
    • checking in to version control (either per-repo or a .dotfiles repo)
    • sharing/distributing within a team

    I'm imagining this could be stored in a number of places, e.g. $HOME/.config/codegate, in the currently open repository, etc. but that decision seems further down the road.

    After speaking with Ozz, I think the best small increment to deliver initially is a small change to the REST API to update/read config. Am going to try and think about the API design such that we don't have to rework it many times towards the desired behaviour.

    A future step might be to use a Docker bind mounts to enable local JSON config idea, in addition to editing it via the CRUD API.

    What I'm imagining a local JSON config could look like in future.

    {
        // ... other global config
        "workspaces": {
            "default": {
                "system_prompt": "",
                "muxing_rules": [
                    {
                        "provider_name": "provider1",
                        "provider_id": "provider1_id",
                        "model": "model1",
                        "matcher_type": "catch_all",
                        "matcher": null
                    },
                    {
                        "provider_name": "provider2",
                        "provider_id": "provider2_id",
                        "model": "model2",
                        "matcher_type": "filename_match",
                        "matcher": "*.py"
                    }
                ]
                // ... other workspace config
            },
            "foo": {
                "system_prompt": "",
                "muxing_rules": [
                    {
                        "provider_name": "provider3",
                        "provider_id": "provider3_id",
                        "model": "model3",
                        "matcher_type": "request_type_match",
                        "matcher": "chat"
                    }
                ]
                // ... other workspace config
            }
        }
    }
  8. lxmcgvrn commented on Mar 4, 2025

    @lxmcgvrn
    Contributor

    Update for posterity, the initial work on this is progressing, it took some time to figure out a good approach for integration testing, but that is in place now too. Will hammer out a few more tests cases and add the GET endpoint for shareable config, then it will be ready.

  9. lxmcgvrn commented on Mar 6, 2025

    @lxmcgvrn
    Contributor

    I have made some progress with endpoints to create/update/read a workspace, although the actual data that we are exporting/uploading contains UUIDs that are specific to a user's instance — so this isn't viable.

    Specifically the instance-specific data is in the mux rules, which specify providers by provider_id.

    curl -s "http://localhost:8989/api/v1/workspaces/default/muxes" | jq
    
    [
      {
        "provider_name": null,
        "provider_id": "945a33df-74d9-4aa8-8f12-43a44f515d23", 
        "model": "x-ai/grok-beta",
        "matcher_type": "filename_match",
        "matcher": "*.py"
      },
      {
        "provider_name": null,
        "provider_id": "0653607e-bf47-42d8-9a9d-86cdca3cf19f",
        "model": "deepseek-r1:1.5b",
        "matcher_type": "catch_all",
        "matcher": ""
      }
    ]
    curl -X PUT http://localhost:8989/api/v1/workspaces/default/muxes \
      -H "Content-Type: application/json" \
      -d '[
            {
              "provider_name": null,
              "provider_id": "945a33df-74d9-4aa8-8f12-43a44f515d23",
              "model": "anthropic/claude-3-opus:beta",
              "matcher_type": "filename_match",
              "matcher": "*.py"
            },
            {
              "provider_name": null,
              "provider_id": "0653607e-bf47-42d8-9a9d-86cdca3cf19f",
              "model": "deepseek-r1:1.5b",
              "matcher_type": "catch_all",
              "matcher": ""
            }
         ]'

    Idea 1: refactor muxing to remove the instance specific provider_id from a rule

    This seems like a lot of work upfront, and may be closing some doors to future
    requirements that I'm not aware of yet.

    However, I think it would also simplify things for this use case, and for
    file-based configuration.

    As part of this idea, I think this would be wise to enforce a unique constraint on provider_type in the
    provider_endpoints table. There is probably a tricky, opinionated migration
    involved in this that may discard some user configuration, although given we're in the very early stage of product
    development, I think this is acceptable.

    All told, this would allow creating/updating a workspace to look like this

    curl -X POST http://localhost:8989/api/v1/workspaces \
      -H "Content-Type: application/json" \
      -d '{
              "name": "my-workspace",
              "config": {
                          "custom_instructions": "Respond in prose",
                          "muxing_rules": [
                              {
    -                             "provider_name": null,
    -                             "provider_id": "945a33df-74d9-4aa8-8f12-43a44f515d23",
    +                             "provider_type": "openrouter",
                                  "matcher": "*.js",
                                  "matcher_type": "filename_match",
                              }
                          ],
                      },
          }'
    • and then exporting a workspace would produce a compatible JSON blob like
      this
    curl -s "http://localhost:8989/api/v1/workspaces/default"
    {
      "name": "default",
      "config": {
          "custom_instructions": "foo",
          "muxing_rules": [
            {
    -           "provider_name": null,
    -           "provider_id": "945a33df-74d9-4aa8-8f12-43a44f515d23",
    +           "provider_type": "openrouter",
                "model": "x-ai/grok-beta",
                "matcher_type": "filename_match",
                "matcher": "*.py"
            },
            {
    -           "provider_name": null,
    -           "provider_id": "0653607e-bf47-42d8-9a9d-86cdca3cf19f",
    +           "provider_type": "ollama",
                "model": "deepseek-r1:1.5b",
                "matcher_type": "catch_all",
                "matcher": ""
            }
          ]
      }
    }

    Idea 2: Fallback logic for finding provider by ID / name / type

    There is another approach, which is simply to make the provider_id and
    provider_type optional in a MuxRule, and update all CRUD operations to use
    fallback logic to attempt to find a provider by type, or name, if the ID is not
    present, although my concern is that this might not produce the most
    deterministic results if there are multiple providers with the same type.

    An example implementation might look like this:

    def get_provider(provider_id=None, provider_type=None):
        if provider_id:
            provider = find_provider_by_id(provider_id)
            if provider:
                return provider
        if provider_type:
            providers = find_providers_by_type(provider_type)
            if len(providers) == 1:
                return providers[0]
            elif len(providers) > 1:
                raise Exception("Multiple providers found for type: {}".format(provider_type))
        raise Exception("Provider not found")
    
    # Example usage in a CRUD operation
    def create_mux_rule(data):
        provider = get_provider(provider_id=data.get('provider_id'), provider_type=data.get('provider_type'))
        if not provider:
            raise Exception("Provider not found")
        # Continue with creating the mux rule using the provider
  10. JAORMX commented on Mar 6, 2025

    @JAORMX
    Contributor

    For the record, we had an out of band discussion about this and went for option two; with the caveat that the parameters will only be checked on create/update.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions