multiwoven-integrations 0.40.0 → 0.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/multiwoven/integrations/config.rb +4 -1
  3. data/lib/multiwoven/integrations/core/base_connector.rb +33 -6
  4. data/lib/multiwoven/integrations/core/constants.rb +1 -0
  5. data/lib/multiwoven/integrations/core/open_router_catalog.rb +212 -0
  6. data/lib/multiwoven/integrations/protocol/protocol.json +54 -0
  7. data/lib/multiwoven/integrations/protocol/protocol.rb +39 -1
  8. data/lib/multiwoven/integrations/rollout.rb +3 -1
  9. data/lib/multiwoven/integrations/service.rb +17 -8
  10. data/lib/multiwoven/integrations/source/aisquared/config/meta.json +8 -2
  11. data/lib/multiwoven/integrations/source/aisquared/config/models.json +120 -0
  12. data/lib/multiwoven/integrations/source/aisquared/config/spec.json +6 -1
  13. data/lib/multiwoven/integrations/source/anthropic/config/meta.json +9 -2
  14. data/lib/multiwoven/integrations/source/anthropic/config/models.json +4 -0
  15. data/lib/multiwoven/integrations/source/anthropic/config/spec.json +7 -1
  16. data/lib/multiwoven/integrations/source/aws_bedrock_model/config/meta.json +8 -2
  17. data/lib/multiwoven/integrations/source/aws_bedrock_model/config/models.json +96 -0
  18. data/lib/multiwoven/integrations/source/aws_sagemaker_model/config/meta.json +8 -2
  19. data/lib/multiwoven/integrations/source/databrics_model/config/meta.json +20 -15
  20. data/lib/multiwoven/integrations/source/epic_fhir/client.rb +47 -14
  21. data/lib/multiwoven/integrations/source/generic_open_ai/client.rb +15 -8
  22. data/lib/multiwoven/integrations/source/generic_open_ai/config/meta.json +8 -1
  23. data/lib/multiwoven/integrations/source/google_gemini/client.rb +18 -0
  24. data/lib/multiwoven/integrations/source/google_gemini/config/catalog.json +6 -0
  25. data/lib/multiwoven/integrations/source/google_gemini/config/meta.json +23 -0
  26. data/lib/multiwoven/integrations/source/google_gemini/config/models.json +26 -0
  27. data/lib/multiwoven/integrations/source/google_gemini/config/spec.json +71 -0
  28. data/lib/multiwoven/integrations/source/google_gemini/icon.svg +10 -0
  29. data/lib/multiwoven/integrations/source/google_vertex_model/config/meta.json +7 -2
  30. data/lib/multiwoven/integrations/source/http_model/config/meta.json +7 -1
  31. data/lib/multiwoven/integrations/source/john_snow_labs/client.rb +18 -0
  32. data/lib/multiwoven/integrations/source/john_snow_labs/config/catalog.json +6 -0
  33. data/lib/multiwoven/integrations/source/john_snow_labs/config/meta.json +24 -0
  34. data/lib/multiwoven/integrations/source/john_snow_labs/config/models.json +119 -0
  35. data/lib/multiwoven/integrations/source/john_snow_labs/config/spec.json +71 -0
  36. data/lib/multiwoven/integrations/source/john_snow_labs/icon.svg +16 -0
  37. data/lib/multiwoven/integrations/source/open_ai/config/meta.json +9 -2
  38. data/lib/multiwoven/integrations/source/open_ai/config/models.json +26 -0
  39. data/lib/multiwoven/integrations/source/open_ai/config/spec.json +7 -1
  40. data/lib/multiwoven/integrations/source/watsonx_ai/config/meta.json +8 -2
  41. data/lib/multiwoven/integrations/source/watsonx_ai/config/models.json +73 -0
  42. data/lib/multiwoven/integrations.rb +4 -0
  43. metadata +20 -2
@@ -6,7 +6,13 @@
6
6
  "$schema": "http://json-schema.org/draft-07/schema#",
7
7
  "title": "Anthropic Endpoint",
8
8
  "type": "object",
9
- "required": ["api_key", "request_format", "response_format"],
9
+ "x-dynamic-input-path": "messages.0.content",
10
+ "x-output-path": "content.0.text",
11
+ "required": [
12
+ "api_key",
13
+ "request_format",
14
+ "response_format"
15
+ ],
10
16
  "properties": {
11
17
  "api_key": {
12
18
  "type": "string",
@@ -1,16 +1,22 @@
1
1
  {
2
2
  "data": {
3
3
  "name": "AwsBedrockModel",
4
- "title": "AWS Bedrock Model",
4
+ "title": "Amazon Bedrock",
5
5
  "connector_type": "source",
6
6
  "category": "AI Model",
7
7
  "sub_category": "LLM",
8
+ "provider_type": "cloud_provider",
9
+ "display_order": 40,
10
+ "description": "Access foundation models via AWS Bedrock. Supports Titan, Claude via AWS, Llama, Mistral, and more via your AWS credentials.",
8
11
  "documentation_url": "https://docs.squared.ai/activation/ai-ml-sources/aws_bedrock-model",
9
12
  "github_issue_label": "source-aws-bedrock-model",
10
13
  "icon": "icon.svg",
11
14
  "license": "MIT",
12
15
  "release_stage": "alpha",
13
16
  "support_level": "community",
14
- "tags": ["language:ruby", "multiwoven"]
17
+ "tags": [
18
+ "language:ruby",
19
+ "multiwoven"
20
+ ]
15
21
  }
16
22
  }
@@ -0,0 +1,96 @@
1
+ {
2
+ "models": [
3
+ {
4
+ "id": "anthropic.claude-sonnet-4-5-20250929-v1:0",
5
+ "name": "Claude Sonnet 4.5 (Bedrock)",
6
+ "model_type": "llm",
7
+ "type": "completion",
8
+ "tasks": [
9
+ "Text Generation",
10
+ "Reasoning",
11
+ "Analysis"
12
+ ],
13
+ "context_window": 200000,
14
+ "max_output": 64000,
15
+ "pricing": {
16
+ "input": 3.0,
17
+ "output": 15.0,
18
+ "cached_read": 0.3,
19
+ "cached_write": 3.75,
20
+ "unit": "per_1m_tokens"
21
+ },
22
+ "capabilities": [
23
+ "Documents",
24
+ "Image analysis",
25
+ "Data analyst"
26
+ ]
27
+ },
28
+ {
29
+ "id": "amazon.titan-text-premier-v1:0",
30
+ "name": "Titan Text Premier",
31
+ "model_type": "llm",
32
+ "type": "completion",
33
+ "tasks": [
34
+ "Text Generation",
35
+ "Chat"
36
+ ],
37
+ "context_window": 32000,
38
+ "max_output": 3072,
39
+ "pricing": {
40
+ "input": 0.5,
41
+ "output": 1.5,
42
+ "cached_read": null,
43
+ "cached_write": null,
44
+ "unit": "per_1m_tokens"
45
+ },
46
+ "capabilities": [
47
+ "Documents"
48
+ ]
49
+ },
50
+ {
51
+ "id": "meta.llama3-70b-instruct-v1:0",
52
+ "name": "Llama 3 70B Instruct",
53
+ "model_type": "llm",
54
+ "type": "completion",
55
+ "tasks": [
56
+ "Text Generation",
57
+ "Reasoning"
58
+ ],
59
+ "context_window": 8192,
60
+ "max_output": 2048,
61
+ "pricing": {
62
+ "input": 2.65,
63
+ "output": 3.5,
64
+ "cached_read": null,
65
+ "cached_write": null,
66
+ "unit": "per_1m_tokens"
67
+ },
68
+ "capabilities": [
69
+ "Documents"
70
+ ]
71
+ },
72
+ {
73
+ "id": "amazon.titan-embed-text-v2:0",
74
+ "name": "Titan Text Embeddings V2",
75
+ "model_type": "embedding",
76
+ "type": "embedding",
77
+ "tasks": [
78
+ "Text Embeddings",
79
+ "Indexing",
80
+ "Retrieval"
81
+ ],
82
+ "context_window": 8192,
83
+ "max_output": null,
84
+ "pricing": {
85
+ "input": 0.02,
86
+ "output": null,
87
+ "cached_read": null,
88
+ "cached_write": null,
89
+ "unit": "per_1m_tokens"
90
+ },
91
+ "capabilities": [
92
+ "Documents"
93
+ ]
94
+ }
95
+ ]
96
+ }
@@ -1,16 +1,22 @@
1
1
  {
2
2
  "data": {
3
3
  "name": "AwsSagemakerModel",
4
- "title": "AWS Sagemaker Model",
4
+ "title": "AWS SageMaker",
5
5
  "connector_type": "source",
6
6
  "category": "AI Model",
7
7
  "sub_category": "AI_ML Service",
8
+ "provider_type": "cloud_provider",
9
+ "display_order": 80,
10
+ "description": "Deploy and serve custom models via AWS SageMaker endpoints. Supports any model you have hosted on SageMaker.",
8
11
  "documentation_url": "https://docs.squared.ai/guides/sources/data-sources/aws_sagemaker-model",
9
12
  "github_issue_label": "source-aws-sagemaker-model",
10
13
  "icon": "icon.svg",
11
14
  "license": "MIT",
12
15
  "release_stage": "alpha",
13
16
  "support_level": "community",
14
- "tags": ["language:ruby", "multiwoven"]
17
+ "tags": [
18
+ "language:ruby",
19
+ "multiwoven"
20
+ ]
15
21
  }
16
22
  }
@@ -1,17 +1,22 @@
1
1
  {
2
- "data": {
3
- "name": "DatabricksModel",
4
- "title": "Databricks Model",
5
- "connector_type": "source",
6
- "category": "AI Model",
7
- "sub_category": "AI_ML Service",
8
- "documentation_url": "https://docs.squared.ai/guides/sources/data-sources/databricks-model",
9
- "github_issue_label": "source-databricks-foundation",
10
- "icon": "icon.svg",
11
- "license": "MIT",
12
- "release_stage": "alpha",
13
- "support_level": "community",
14
- "tags": ["language:ruby", "multiwoven"]
15
- }
2
+ "data": {
3
+ "name": "DatabricksModel",
4
+ "title": "Databricks",
5
+ "connector_type": "source",
6
+ "category": "AI Model",
7
+ "sub_category": "AI_ML Service",
8
+ "provider_type": "cloud_provider",
9
+ "display_order": 100,
10
+ "description": "Serve models from Databricks Model Serving endpoints using your workspace credentials.",
11
+ "documentation_url": "https://docs.squared.ai/guides/sources/data-sources/databricks-model",
12
+ "github_issue_label": "source-databricks-foundation",
13
+ "icon": "icon.svg",
14
+ "license": "MIT",
15
+ "release_stage": "alpha",
16
+ "support_level": "community",
17
+ "tags": [
18
+ "language:ruby",
19
+ "multiwoven"
20
+ ]
16
21
  }
17
-
22
+ }
@@ -8,6 +8,7 @@ module Multiwoven::Integrations::Source
8
8
  NDJSON_ACCEPT = "application/fhir+ndjson"
9
9
  DEFAULT_EXPORT_POLL_INTERVAL = 5
10
10
  DEFAULT_EXPORT_TIMEOUT = 120
11
+ CONCURRENT_EXPORT_MESSAGE = "Another request for this same Client and Group is in progress."
11
12
  REQUIRED_CONFIG_KEYS = %w[fhir_base_url token_url client_id private_key kid export_group_id].freeze
12
13
  DEFAULT_RESOURCES = %w[
13
14
  AllergyIntolerance
@@ -203,36 +204,68 @@ module Multiwoven::Integrations::Source
203
204
  end
204
205
 
205
206
  def run_bulk_export(connection_config, resource_type)
206
- status_url = kickoff_bulk_export(connection_config, resource_type)
207
- poll_bulk_export(connection_config, status_url)
207
+ deadline = Time.now + export_timeout(connection_config)
208
+ status_url = kickoff_bulk_export(connection_config, resource_type, deadline: deadline)
209
+ poll_bulk_export(connection_config, status_url, deadline: deadline)
208
210
  end
209
211
 
210
- def kickoff_bulk_export(connection_config, resource_type)
212
+ def kickoff_bulk_export(connection_config, resource_type, deadline:)
211
213
  url = bulk_export_url(connection_config, resource_type)
212
- response = fhir_get(connection_config, url, extra_headers: { "Prefer" => "respond-async" })
213
- raise fhir_api_error(response, url) unless response.code.to_s == "202"
214
214
 
215
- status_url = response["content-location"].presence
216
- raise StandardError, "Epic FHIR 202 #{url} missing Content-Location header" if status_url.nil?
215
+ loop do
216
+ response = fhir_get(connection_config, url, extra_headers: { "Prefer" => "respond-async" })
217
+ if response.code.to_s == "202"
218
+ status_url = response["content-location"].presence
219
+ raise StandardError, "Epic FHIR 202 #{url} missing Content-Location header" if status_url.nil?
217
220
 
218
- status_url
219
- end
221
+ return status_url
222
+ end
220
223
 
221
- def poll_bulk_export(connection_config, status_url)
222
- timeout = export_timeout(connection_config)
223
- deadline = Time.now + timeout
224
+ raise fhir_api_error(response, url) unless concurrent_export?(response)
225
+ raise concurrent_export_timeout_error unless wait_for_retry?(connection_config, response, deadline)
226
+ end
227
+ end
224
228
 
229
+ def poll_bulk_export(connection_config, status_url, deadline:)
225
230
  loop do
226
231
  response = fhir_get(connection_config, status_url)
227
232
  code = response.code.to_s
228
233
  return JSON.parse(response.body) if code == "200"
229
234
  raise fhir_api_error(response, status_url) unless code == "202"
230
- raise StandardError, "Epic FHIR 202 #{status_url} still in progress after #{timeout}s" if Time.now >= deadline
231
235
 
232
- sleep(retry_after(response) || export_poll_interval(connection_config))
236
+ unless wait_for_retry?(connection_config, response, deadline)
237
+ raise StandardError,
238
+ "Epic FHIR 202 #{status_url} still in progress after #{export_timeout(connection_config)}s"
239
+ end
233
240
  end
234
241
  end
235
242
 
243
+ # Waits between attempts without ever waiting past the shared export
244
+ # deadline: sleeping longer and then retrying would issue a request the
245
+ # caller has already given up on, and Epic counts it as one more
246
+ # concurrent export for this client and group.
247
+ def wait_for_retry?(connection_config, response, deadline)
248
+ remaining = deadline - Time.now
249
+ return false unless remaining.positive?
250
+
251
+ delay = retry_after(response) || export_poll_interval(connection_config)
252
+ return false if delay > remaining
253
+
254
+ sleep(delay)
255
+ true
256
+ end
257
+
258
+ def concurrent_export?(response)
259
+ response.body.to_s.downcase.include?(CONCURRENT_EXPORT_MESSAGE.downcase)
260
+ end
261
+
262
+ def concurrent_export_timeout_error
263
+ StandardError.new(
264
+ "Epic is still preparing another bulk export for this Client and Group. " \
265
+ "Retry after the existing export completes."
266
+ )
267
+ end
268
+
236
269
  def download_bulk_output(connection_config, manifest, resource_type, limit:, offset:)
237
270
  return [] if limit&.zero?
238
271
 
@@ -15,7 +15,7 @@ module Multiwoven::Integrations::Source
15
15
  )
16
16
  success?(response) ? success_status : failure_status(nil)
17
17
  rescue StandardError => e
18
- handle_exception(e, { context: "GENERIC OPEN AI:CHECK_CONNECTION:EXCEPTION", type: "error" })
18
+ handle_exception(e, { context: "#{log_context}:CHECK_CONNECTION:EXCEPTION", type: "error" })
19
19
  failure_status(e)
20
20
  end
21
21
 
@@ -24,7 +24,7 @@ module Multiwoven::Integrations::Source
24
24
  catalog = build_catalog(catalog_json)
25
25
  catalog.to_multiwoven_message
26
26
  rescue StandardError => e
27
- handle_exception(e, { context: "GENERIC OPEN AI:DISCOVER:EXCEPTION", type: "error" })
27
+ handle_exception(e, { context: "#{log_context}:DISCOVER:EXCEPTION", type: "error" })
28
28
  end
29
29
 
30
30
  def read(sync_config)
@@ -41,11 +41,18 @@ module Multiwoven::Integrations::Source
41
41
  run_model(connection_config, payload)
42
42
  end
43
43
  rescue StandardError => e
44
- handle_exception(e, { context: "GENERIC OPEN AI:READ:EXCEPTION", type: "error" })
44
+ handle_exception(e, { context: "#{log_context}:READ:EXCEPTION", type: "error" })
45
45
  end
46
46
 
47
47
  private
48
48
 
49
+ # Prefixes this connector's log lines. Subclasses that reuse this client
50
+ # for another OpenAI-compatible provider override it so their exceptions
51
+ # are attributable.
52
+ def log_context
53
+ "GENERIC OPEN AI"
54
+ end
55
+
49
56
  def prepare_config(config)
50
57
  config.with_indifferent_access.tap do |conf|
51
58
  conf[:config][:timeout] ||= 30
@@ -55,7 +62,7 @@ module Multiwoven::Integrations::Source
55
62
  def parse_json(json_string)
56
63
  JSON.parse(json_string)
57
64
  rescue JSON::ParserError => e
58
- handle_exception(e, { context: "GENERIC OPEN AI:PARSE_JSON:EXCEPTION", type: "error" })
65
+ handle_exception(e, { context: "#{log_context}:PARSE_JSON:EXCEPTION", type: "error" })
59
66
  {}
60
67
  end
61
68
 
@@ -69,7 +76,7 @@ module Multiwoven::Integrations::Source
69
76
  )
70
77
  process_response(response)
71
78
  rescue StandardError => e
72
- handle_exception(e, { context: "GENERIC OPEN AI:RUN_MODEL:EXCEPTION", type: "error" })
79
+ handle_exception(e, { context: "#{log_context}:RUN_MODEL:EXCEPTION", type: "error" })
73
80
  end
74
81
 
75
82
  def run_model_stream(connection_config, payload)
@@ -83,7 +90,7 @@ module Multiwoven::Integrations::Source
83
90
  process_streaming_response(chunk) { |message| yield message if block_given? }
84
91
  end
85
92
  rescue StandardError => e
86
- handle_exception(e, { context: "GENERIC OPEN AI:RUN_STREAM_MODEL:EXCEPTION", type: "error" })
93
+ handle_exception(e, { context: "#{log_context}:RUN_STREAM_MODEL:EXCEPTION", type: "error" })
87
94
  end
88
95
 
89
96
  def process_response(response)
@@ -91,10 +98,10 @@ module Multiwoven::Integrations::Source
91
98
  data = JSON.parse(response.body)
92
99
  [RecordMessage.new(data: data, emitted_at: Time.now.to_i).to_multiwoven_message]
93
100
  else
94
- create_log_message("GENERIC OPEN AI:RUN_MODEL", "error", "request failed: #{response.body}")
101
+ create_log_message("#{log_context}:RUN_MODEL", "error", "request failed: #{response.body}")
95
102
  end
96
103
  rescue StandardError => e
97
- handle_exception(e, { context: "OPEN AI:PROCESS_RESPONSE:EXCEPTION", type: "error" })
104
+ handle_exception(e, { context: "#{log_context}:PROCESS_RESPONSE:EXCEPTION", type: "error" })
98
105
  end
99
106
 
100
107
  def extract_data_entries(chunk)
@@ -5,12 +5,19 @@
5
5
  "connector_type": "source",
6
6
  "category": "AI Model",
7
7
  "sub_category": "LLM",
8
+ "provider_type": "third_party",
9
+ "display_order": 120,
10
+ "description": "Connect any endpoint that implements the OpenAI API specification.",
11
+ "show_payload_formats": true,
8
12
  "documentation_url": "https://docs.squared.ai/activation/ai-ml-sources/generic_open_ai-endpoint",
9
13
  "github_issue_label": "source-generic-open-ai-model",
10
14
  "icon": "icon.svg",
11
15
  "license": "MIT",
12
16
  "release_stage": "alpha",
13
17
  "support_level": "community",
14
- "tags": ["language:ruby", "multiwoven"]
18
+ "tags": [
19
+ "language:ruby",
20
+ "multiwoven"
21
+ ]
15
22
  }
16
23
  }
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Multiwoven::Integrations::Source
4
+ module GoogleGemini
5
+ include Multiwoven::Integrations::Core
6
+ # Gemini exposes an OpenAI-compatible chat completions API, so the request,
7
+ # streaming and response handling is identical to GenericOpenAI. Only the
8
+ # config/ directory differs, and BaseConnector#read_json resolves that from
9
+ # this class's own source location.
10
+ class Client < GenericOpenAI::Client
11
+ private
12
+
13
+ def log_context
14
+ "GOOGLE GEMINI"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ {
2
+ "request_rate_limit": 600,
3
+ "request_rate_limit_unit": "minute",
4
+ "request_rate_concurrency": 10,
5
+ "streams": []
6
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "data": {
3
+ "name": "GoogleGemini",
4
+ "title": "Google Gemini",
5
+ "connector_type": "source",
6
+ "category": "AI Model",
7
+ "sub_category": "LLM",
8
+ "provider_type": "third_party",
9
+ "display_order": 70,
10
+ "openrouter_slug": "google",
11
+ "description": "Gemini model family from Google. Multimodal capabilities with strong performance on reasoning, code generation, and long-context tasks.",
12
+ "documentation_url": "https://ai.google.dev/gemini-api/docs/openai",
13
+ "github_issue_label": "source-google-gemini",
14
+ "icon": "icon.svg",
15
+ "license": "MIT",
16
+ "release_stage": "alpha",
17
+ "support_level": "community",
18
+ "tags": [
19
+ "language:ruby",
20
+ "multiwoven"
21
+ ]
22
+ }
23
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "//models": "Sourced live from OpenRouter. Embedding models are curated here because OpenRouter lists none.",
3
+ "models": [
4
+ {
5
+ "id": "text-embedding-004",
6
+ "name": "Text Embedding 004",
7
+ "model_type": "embedding",
8
+ "type": "embedding",
9
+ "tasks": [
10
+ "Text Embeddings"
11
+ ],
12
+ "context_window": 2048,
13
+ "max_output": null,
14
+ "pricing": {
15
+ "input": 0.0,
16
+ "output": null,
17
+ "cached_read": null,
18
+ "cached_write": null,
19
+ "unit": "per_1m_tokens"
20
+ },
21
+ "capabilities": [
22
+ "Documents"
23
+ ]
24
+ }
25
+ ]
26
+ }
@@ -0,0 +1,71 @@
1
+ {
2
+ "documentation_url": "https://ai.google.dev/gemini-api/docs/openai",
3
+ "stream_type": "user_defined",
4
+ "connector_query_type": "ai_ml",
5
+ "connection_specification": {
6
+ "$schema": "http://json-schema.org/draft-07/schema#",
7
+ "title": "Google Gemini",
8
+ "type": "object",
9
+ "x-dynamic-input-path": "messages.0.content",
10
+ "x-output-path": "choices.0.message.content",
11
+ "required": [
12
+ "url",
13
+ "api_key",
14
+ "request_format",
15
+ "response_format"
16
+ ],
17
+ "properties": {
18
+ "url": {
19
+ "type": "string",
20
+ "title": "Endpoint URL",
21
+ "description": "The Gemini OpenAI-compatible chat completions endpoint.",
22
+ "default": "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions",
23
+ "order": 0
24
+ },
25
+ "api_key": {
26
+ "type": "string",
27
+ "multiwoven_secret": true,
28
+ "title": "API Key",
29
+ "description": "Your Google AI Studio API key.",
30
+ "order": 1
31
+ },
32
+ "is_stream": {
33
+ "type": "boolean",
34
+ "title": "Enable streaming",
35
+ "description": "Enables data streaming when supported by the model. When true, responses are processed in chunks for immediate delivery. Default is false.",
36
+ "default": false,
37
+ "order": 2
38
+ },
39
+ "config": {
40
+ "title": "",
41
+ "type": "object",
42
+ "properties": {
43
+ "timeout": {
44
+ "type": "string",
45
+ "default": "30",
46
+ "title": "HTTP Timeout",
47
+ "description": "The maximum time, in seconds, to wait for a response from the server before the request is canceled.",
48
+ "order": 0
49
+ }
50
+ },
51
+ "order": 3
52
+ },
53
+ "request_format": {
54
+ "title": "Request Format",
55
+ "description": "Sample Request Format",
56
+ "type": "string",
57
+ "default": "{\"model\":\"gemini-2.0-flash\", \"messages\":[{\"role\": \"user\", \"content\": \"What do you know about APIs?\"}], \"stream\": false}",
58
+ "x-request-format": true,
59
+ "order": 4
60
+ },
61
+ "response_format": {
62
+ "title": "Response Format",
63
+ "description": "Sample Response Format",
64
+ "type": "string",
65
+ "default": "{\"choices\":[{\"index\": 0, \"message\":{\"role\": \"assistant\", \"content\": \"APIs let software applications communicate with each other.\"}, \"finish_reason\": \"stop\"}]}",
66
+ "x-response-format": true,
67
+ "order": 5
68
+ }
69
+ }
70
+ }
71
+ }
@@ -0,0 +1,10 @@
1
+ <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <linearGradient id="geminiSparkle" x1="6" y1="34" x2="34" y2="6" gradientUnits="userSpaceOnUse">
4
+ <stop offset="0" stop-color="#1C7DFF"/>
5
+ <stop offset="0.52" stop-color="#1C69FF"/>
6
+ <stop offset="1" stop-color="#F0DCD6"/>
7
+ </linearGradient>
8
+ </defs>
9
+ <path d="M20 4c1.1 6.2 5.8 10.9 12 12-6.2 1.1-10.9 5.8-12 12-1.1-6.2-5.8-10.9-12-12 6.2-1.1 10.9-5.8 12-12Z" fill="url(#geminiSparkle)"/>
10
+ </svg>
@@ -5,13 +5,18 @@
5
5
  "connector_type": "source",
6
6
  "category": "AI Model",
7
7
  "sub_category": "AI_ML Service",
8
+ "provider_type": "cloud_provider",
9
+ "display_order": 90,
10
+ "description": "Access Gemini and other models via Google Vertex AI. Enterprise security, VPC deployment, and data residency controls.",
8
11
  "documentation_url": "https://docs.squared.ai/activation/ai-ml-sources/google_vertex-model",
9
12
  "github_issue_label": "source-vertex",
10
13
  "icon": "icon.svg",
11
14
  "license": "MIT",
12
15
  "release_stage": "alpha",
13
16
  "support_level": "community",
14
- "tags": ["language:ruby", "multiwoven"]
17
+ "tags": [
18
+ "language:ruby",
19
+ "multiwoven"
20
+ ]
15
21
  }
16
22
  }
17
-
@@ -5,12 +5,18 @@
5
5
  "connector_type": "source",
6
6
  "category": "AI Model",
7
7
  "sub_category": "AI_ML Service",
8
+ "provider_type": "cloud_provider",
9
+ "display_order": 110,
10
+ "description": "Connect any model exposed over HTTP by describing its request and response format.",
8
11
  "documentation_url": "https://docs.squared.ai/activation/ai-ml-sources/http-model-endpoint",
9
12
  "github_issue_label": "source-http-model",
10
13
  "icon": "icon.svg",
11
14
  "license": "MIT",
12
15
  "release_stage": "alpha",
13
16
  "support_level": "community",
14
- "tags": ["language:ruby", "multiwoven"]
17
+ "tags": [
18
+ "language:ruby",
19
+ "multiwoven"
20
+ ]
15
21
  }
16
22
  }
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Multiwoven::Integrations::Source
4
+ module JohnSnowLabs
5
+ include Multiwoven::Integrations::Core
6
+ # John Snow Labs exposes an OpenAI-compatible chat completions API, so the request,
7
+ # streaming and response handling is identical to GenericOpenAI. Only the
8
+ # config/ directory differs, and BaseConnector#read_json resolves that from
9
+ # this class's own source location.
10
+ class Client < GenericOpenAI::Client
11
+ private
12
+
13
+ def log_context
14
+ "JOHN SNOW LABS"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,6 @@
1
+ {
2
+ "request_rate_limit": 600,
3
+ "request_rate_limit_unit": "minute",
4
+ "request_rate_concurrency": 10,
5
+ "streams": []
6
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "data": {
3
+ "name": "JohnSnowLabs",
4
+ "title": "John Snow Labs",
5
+ "connector_type": "source",
6
+ "category": "AI Model",
7
+ "sub_category": "LLM",
8
+ "provider_type": "partner_provider",
9
+ "display_order": 50,
10
+ "description": "Spark NLP and healthcare AI models deployed and managed by AISquared. Clinical NLP, NER, and domain-specific models for life sciences and healthcare verticals.",
11
+ "managed_by_ais": true,
12
+ "documentation_url": "https://nlp.johnsnowlabs.com/",
13
+ "github_issue_label": "source-john-snow-labs",
14
+ "icon": "icon.svg",
15
+ "license": "MIT",
16
+ "release_stage": "alpha",
17
+ "support_level": "partner",
18
+ "tags": [
19
+ "language:ruby",
20
+ "multiwoven",
21
+ "partner:john-snow-labs"
22
+ ]
23
+ }
24
+ }