parse-stack-next 4.5.0 → 5.0.1
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.
- checksums.yaml +4 -4
- data/.bundle/config +2 -0
- data/.env.sample +17 -3
- data/.github/workflows/codeql.yml +44 -0
- data/.github/workflows/docs.yml +39 -0
- data/.github/workflows/release.yml +32 -0
- data/.github/workflows/ruby.yml +8 -6
- data/.gitignore +4 -0
- data/.vscode/settings.json +3 -0
- data/CHANGELOG.md +305 -72
- data/Gemfile.lock +10 -3
- data/LICENSE.txt +1 -1
- data/README.md +190 -219
- data/Rakefile +1 -1
- data/SECURITY.md +30 -0
- data/assets/parse-stack-next-avatar.png +0 -0
- data/assets/parse-stack-next-avatar.svg +37 -0
- data/assets/parse-stack-next-banner.png +0 -0
- data/assets/parse-stack-next-banner.svg +45 -0
- data/assets/parse-stack-next-social-preview.png +0 -0
- data/docs/atlas_vector_search_guide.md +511 -0
- data/docs/client_sdk_guide.md +1320 -0
- data/docs/mcp_guide.md +225 -104
- data/docs/mongodb_direct_guide.md +21 -4
- data/docs/usage_guide.md +585 -0
- data/examples/transaction_example.rb +28 -28
- data/lib/parse/acl_scope.rb +2 -2
- data/lib/parse/agent/mcp_rack_app.rb +184 -16
- data/lib/parse/agent/metadata_dsl.rb +16 -16
- data/lib/parse/agent/pipeline_validator.rb +28 -1
- data/lib/parse/agent/prompts.rb +5 -5
- data/lib/parse/agent/tools.rb +287 -14
- data/lib/parse/agent.rb +209 -12
- data/lib/parse/api/analytics.rb +27 -5
- data/lib/parse/api/files.rb +6 -2
- data/lib/parse/api/push.rb +21 -4
- data/lib/parse/api/server.rb +59 -0
- data/lib/parse/api/users.rb +26 -2
- data/lib/parse/atlas_search/index_manager.rb +84 -0
- data/lib/parse/atlas_search.rb +37 -9
- data/lib/parse/cache/pool.rb +88 -0
- data/lib/parse/cache/redis.rb +249 -0
- data/lib/parse/client/body_builder.rb +94 -0
- data/lib/parse/client/caching.rb +109 -9
- data/lib/parse/client/response.rb +27 -0
- data/lib/parse/client.rb +74 -3
- data/lib/parse/console.rb +203 -0
- data/lib/parse/embeddings/cohere.rb +484 -0
- data/lib/parse/embeddings/fixture.rb +130 -0
- data/lib/parse/embeddings/jina.rb +454 -0
- data/lib/parse/embeddings/local_http.rb +492 -0
- data/lib/parse/embeddings/openai.rb +520 -0
- data/lib/parse/embeddings/provider.rb +264 -0
- data/lib/parse/embeddings/qwen.rb +431 -0
- data/lib/parse/embeddings/voyage.rb +550 -0
- data/lib/parse/embeddings.rb +225 -0
- data/lib/parse/graphql/scalars.rb +53 -0
- data/lib/parse/graphql/type_generator.rb +264 -0
- data/lib/parse/graphql.rb +48 -0
- data/lib/parse/live_query/client.rb +24 -5
- data/lib/parse/live_query/subscription.rb +17 -6
- data/lib/parse/live_query.rb +9 -4
- data/lib/parse/model/associations/collection_proxy.rb +2 -2
- data/lib/parse/model/associations/has_many.rb +32 -1
- data/lib/parse/model/associations/has_one.rb +17 -0
- data/lib/parse/model/associations/pointer_collection_proxy.rb +3 -3
- data/lib/parse/model/classes/user.rb +307 -11
- data/lib/parse/model/clp.rb +1 -1
- data/lib/parse/model/core/create_lock.rb +14 -2
- data/lib/parse/model/core/embed_managed.rb +296 -0
- data/lib/parse/model/core/fetching.rb +4 -4
- data/lib/parse/model/core/indexing.rb +53 -14
- data/lib/parse/model/core/parse_reference.rb +3 -3
- data/lib/parse/model/core/properties.rb +70 -1
- data/lib/parse/model/core/querying.rb +57 -1
- data/lib/parse/model/core/vector_searchable.rb +285 -0
- data/lib/parse/model/file.rb +16 -4
- data/lib/parse/model/model.rb +26 -10
- data/lib/parse/model/object.rb +63 -6
- data/lib/parse/model/pointer.rb +16 -2
- data/lib/parse/model/shortnames.rb +2 -0
- data/lib/parse/model/validations/uniqueness_validator.rb +3 -3
- data/lib/parse/model/vector.rb +102 -0
- data/lib/parse/mongodb.rb +90 -8
- data/lib/parse/pipeline_security.rb +59 -2
- data/lib/parse/query/constraints.rb +16 -14
- data/lib/parse/query/ordering.rb +1 -1
- data/lib/parse/query.rb +137 -64
- data/lib/parse/stack/generators/templates/model.erb +2 -2
- data/lib/parse/stack/generators/templates/model_installation.rb +1 -1
- data/lib/parse/stack/generators/templates/model_role.rb +1 -1
- data/lib/parse/stack/generators/templates/model_session.rb +1 -1
- data/lib/parse/stack/generators/templates/parse.rb +1 -1
- data/lib/parse/stack/generators/templates/webhooks.rb +1 -1
- data/lib/parse/stack/version.rb +1 -1
- data/lib/parse/stack.rb +375 -73
- data/lib/parse/two_factor_auth/user_extension.rb +5 -2
- data/lib/parse/vector_search.rb +341 -0
- data/parse-stack-next.gemspec +10 -9
- data/scripts/docker/docker-compose.test.yml +18 -0
- data/scripts/start-parse.sh +6 -0
- data/scripts/vector_prototype/create_vector_index.js +105 -0
- data/scripts/vector_prototype/fetch_embeddings.py +241 -0
- data/scripts/vector_prototype/fixture_manifest.json +9 -0
- data/scripts/vector_prototype/query_prototype.rb +84 -0
- data/scripts/vector_prototype/run.sh +34 -0
- metadata +77 -5
- data/parse-stack.png +0 -0
data/lib/parse/agent/tools.rb
CHANGED
|
@@ -20,8 +20,8 @@ module Parse
|
|
|
20
20
|
# Third-party apps may register additional tools:
|
|
21
21
|
#
|
|
22
22
|
# Parse::Agent::Tools.register(
|
|
23
|
-
# name: :
|
|
24
|
-
# description: "Count
|
|
23
|
+
# name: :breakdown_posts,
|
|
24
|
+
# description: "Count posts grouped by author/...",
|
|
25
25
|
# parameters: { type: "object", properties: {...}, required: [...] },
|
|
26
26
|
# permission: :readonly,
|
|
27
27
|
# timeout: 30,
|
|
@@ -104,6 +104,28 @@ module Parse
|
|
|
104
104
|
},
|
|
105
105
|
required: [],
|
|
106
106
|
},
|
|
107
|
+
output_schema: {
|
|
108
|
+
type: "object",
|
|
109
|
+
properties: {
|
|
110
|
+
tools: {
|
|
111
|
+
type: "array",
|
|
112
|
+
items: {
|
|
113
|
+
type: "object",
|
|
114
|
+
properties: {
|
|
115
|
+
name: { type: "string" },
|
|
116
|
+
category: { type: "string" },
|
|
117
|
+
description: { type: "string" },
|
|
118
|
+
},
|
|
119
|
+
required: %w[name category description],
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
categories: {
|
|
123
|
+
type: "object",
|
|
124
|
+
additionalProperties: { type: "string" },
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
required: %w[tools categories],
|
|
128
|
+
},
|
|
107
129
|
},
|
|
108
130
|
|
|
109
131
|
get_all_schemas: {
|
|
@@ -123,6 +145,42 @@ module Parse
|
|
|
123
145
|
},
|
|
124
146
|
required: [],
|
|
125
147
|
},
|
|
148
|
+
output_schema: {
|
|
149
|
+
type: "object",
|
|
150
|
+
properties: {
|
|
151
|
+
total: { type: "integer", minimum: 0 },
|
|
152
|
+
note: { type: "string" },
|
|
153
|
+
built_in: {
|
|
154
|
+
type: "array",
|
|
155
|
+
items: {
|
|
156
|
+
type: "object",
|
|
157
|
+
properties: {
|
|
158
|
+
name: { type: "string" },
|
|
159
|
+
fields: { type: "integer", minimum: 0 },
|
|
160
|
+
desc: { type: "string" },
|
|
161
|
+
methods: { type: "integer", minimum: 0 },
|
|
162
|
+
},
|
|
163
|
+
required: %w[name fields],
|
|
164
|
+
additionalProperties: true,
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
custom: {
|
|
168
|
+
type: "array",
|
|
169
|
+
items: {
|
|
170
|
+
type: "object",
|
|
171
|
+
properties: {
|
|
172
|
+
name: { type: "string" },
|
|
173
|
+
fields: { type: "integer", minimum: 0 },
|
|
174
|
+
desc: { type: "string" },
|
|
175
|
+
methods: { type: "integer", minimum: 0 },
|
|
176
|
+
},
|
|
177
|
+
required: %w[name fields],
|
|
178
|
+
additionalProperties: true,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
required: %w[total built_in custom],
|
|
183
|
+
},
|
|
126
184
|
},
|
|
127
185
|
|
|
128
186
|
get_schema: {
|
|
@@ -144,6 +202,24 @@ module Parse
|
|
|
144
202
|
},
|
|
145
203
|
required: ["class_name"],
|
|
146
204
|
},
|
|
205
|
+
output_schema: {
|
|
206
|
+
type: "object",
|
|
207
|
+
properties: {
|
|
208
|
+
class_name: { type: "string" },
|
|
209
|
+
type: { type: "string" },
|
|
210
|
+
description: { type: "string" },
|
|
211
|
+
usage: { type: "string" },
|
|
212
|
+
fields: { type: "array", items: { type: "object", additionalProperties: true } },
|
|
213
|
+
indexes: { type: "object", additionalProperties: true },
|
|
214
|
+
permissions: { type: "object", additionalProperties: true },
|
|
215
|
+
agent_methods: { type: "array", items: { type: "object", additionalProperties: true } },
|
|
216
|
+
canonical_filter: { type: "object", additionalProperties: true },
|
|
217
|
+
agent_fields: { type: "array", items: { type: "string" } },
|
|
218
|
+
agent_join_fields: { type: "array", items: { type: "string" } },
|
|
219
|
+
relations: { type: "object", additionalProperties: true },
|
|
220
|
+
},
|
|
221
|
+
required: %w[class_name type fields indexes permissions],
|
|
222
|
+
},
|
|
147
223
|
},
|
|
148
224
|
|
|
149
225
|
query_class: {
|
|
@@ -183,6 +259,50 @@ module Parse
|
|
|
183
259
|
},
|
|
184
260
|
required: ["class_name"],
|
|
185
261
|
},
|
|
262
|
+
# Polymorphic envelope: the default `format: "json"` returns a row
|
|
263
|
+
# envelope (class_name, result_count, pagination, results, ...);
|
|
264
|
+
# `format: "csv"|"markdown"|"table"` returns a text envelope
|
|
265
|
+
# (class_name, format, headers, row_count, output). Declared here as
|
|
266
|
+
# a permissive superset (every key from either envelope is optional
|
|
267
|
+
# except class_name) because MCP 2025-06-18 expects type:object at
|
|
268
|
+
# the outputSchema root, which precludes a top-level oneOf. Clients
|
|
269
|
+
# that need to disambiguate inspect `format` (absent for the json
|
|
270
|
+
# envelope, present for text envelopes).
|
|
271
|
+
output_schema: {
|
|
272
|
+
type: "object",
|
|
273
|
+
properties: {
|
|
274
|
+
class_name: { type: "string" },
|
|
275
|
+
# json envelope
|
|
276
|
+
result_count: { type: "integer", minimum: 0 },
|
|
277
|
+
pagination: {
|
|
278
|
+
type: "object",
|
|
279
|
+
properties: {
|
|
280
|
+
limit: { type: "integer", minimum: 0 },
|
|
281
|
+
skip: { type: "integer", minimum: 0 },
|
|
282
|
+
has_more: { type: "boolean" },
|
|
283
|
+
},
|
|
284
|
+
required: %w[limit skip has_more],
|
|
285
|
+
},
|
|
286
|
+
truncated: { type: "boolean" },
|
|
287
|
+
truncated_note: { type: "string" },
|
|
288
|
+
truncated_include_fields: { type: "object", additionalProperties: true },
|
|
289
|
+
next_call: {
|
|
290
|
+
type: "object",
|
|
291
|
+
properties: {
|
|
292
|
+
tool: { type: "string" },
|
|
293
|
+
arguments: { type: "object", additionalProperties: true },
|
|
294
|
+
},
|
|
295
|
+
required: %w[tool arguments],
|
|
296
|
+
},
|
|
297
|
+
results: { type: "array", items: { type: "object", additionalProperties: true } },
|
|
298
|
+
# csv / markdown / table envelope
|
|
299
|
+
format: { type: "string", enum: %w[csv markdown table] },
|
|
300
|
+
headers: { type: "array", items: { type: "string" } },
|
|
301
|
+
row_count: { type: "integer", minimum: 0 },
|
|
302
|
+
output: { type: "string" },
|
|
303
|
+
},
|
|
304
|
+
required: %w[class_name],
|
|
305
|
+
},
|
|
186
306
|
},
|
|
187
307
|
|
|
188
308
|
count_objects: {
|
|
@@ -204,6 +324,15 @@ module Parse
|
|
|
204
324
|
},
|
|
205
325
|
required: ["class_name"],
|
|
206
326
|
},
|
|
327
|
+
output_schema: {
|
|
328
|
+
type: "object",
|
|
329
|
+
properties: {
|
|
330
|
+
class_name: { type: "string" },
|
|
331
|
+
count: { type: "integer", minimum: 0 },
|
|
332
|
+
constraints: { type: "object" },
|
|
333
|
+
},
|
|
334
|
+
required: %w[class_name count constraints],
|
|
335
|
+
},
|
|
207
336
|
},
|
|
208
337
|
|
|
209
338
|
get_object: {
|
|
@@ -228,6 +357,18 @@ module Parse
|
|
|
228
357
|
},
|
|
229
358
|
required: ["class_name", "object_id"],
|
|
230
359
|
},
|
|
360
|
+
output_schema: {
|
|
361
|
+
type: "object",
|
|
362
|
+
properties: {
|
|
363
|
+
class_name: { type: "string" },
|
|
364
|
+
object_id: { type: "string" },
|
|
365
|
+
created_at: { type: %w[string null] },
|
|
366
|
+
updated_at: { type: %w[string null] },
|
|
367
|
+
object: { type: "object" },
|
|
368
|
+
truncated_include_fields: { type: "object" },
|
|
369
|
+
},
|
|
370
|
+
required: %w[class_name object_id object],
|
|
371
|
+
},
|
|
231
372
|
},
|
|
232
373
|
|
|
233
374
|
get_objects: {
|
|
@@ -253,6 +394,22 @@ module Parse
|
|
|
253
394
|
},
|
|
254
395
|
required: ["class_name", "ids"],
|
|
255
396
|
},
|
|
397
|
+
output_schema: {
|
|
398
|
+
type: "object",
|
|
399
|
+
properties: {
|
|
400
|
+
class_name: { type: "string" },
|
|
401
|
+
objects: {
|
|
402
|
+
type: "object",
|
|
403
|
+
additionalProperties: { type: "object" },
|
|
404
|
+
description: "Map of objectId => fetched object. Empty when no ids resolved.",
|
|
405
|
+
},
|
|
406
|
+
missing: { type: "array", items: { type: "string" } },
|
|
407
|
+
requested: { type: "integer", minimum: 0 },
|
|
408
|
+
found: { type: "integer", minimum: 0 },
|
|
409
|
+
truncated_include_fields: { type: "object" },
|
|
410
|
+
},
|
|
411
|
+
required: %w[class_name objects missing requested found],
|
|
412
|
+
},
|
|
256
413
|
},
|
|
257
414
|
|
|
258
415
|
get_sample_objects: {
|
|
@@ -270,6 +427,16 @@ module Parse
|
|
|
270
427
|
},
|
|
271
428
|
required: ["class_name"],
|
|
272
429
|
},
|
|
430
|
+
output_schema: {
|
|
431
|
+
type: "object",
|
|
432
|
+
properties: {
|
|
433
|
+
class_name: { type: "string" },
|
|
434
|
+
sample_count: { type: "integer", minimum: 0 },
|
|
435
|
+
samples: { type: "array", items: { type: "object" } },
|
|
436
|
+
note: { type: "string" },
|
|
437
|
+
},
|
|
438
|
+
required: %w[class_name sample_count samples],
|
|
439
|
+
},
|
|
273
440
|
},
|
|
274
441
|
|
|
275
442
|
aggregate: {
|
|
@@ -383,6 +550,33 @@ module Parse
|
|
|
383
550
|
},
|
|
384
551
|
required: ["class_name", "field"],
|
|
385
552
|
},
|
|
553
|
+
output_schema: {
|
|
554
|
+
type: "object",
|
|
555
|
+
properties: {
|
|
556
|
+
class_name: { type: "string" },
|
|
557
|
+
field: { type: "string" },
|
|
558
|
+
operation: { type: "string" },
|
|
559
|
+
group_count: { type: "integer", minimum: 0 },
|
|
560
|
+
groups: {
|
|
561
|
+
type: "array",
|
|
562
|
+
items: {
|
|
563
|
+
type: "object",
|
|
564
|
+
properties: {
|
|
565
|
+
key: {},
|
|
566
|
+
value: { type: %w[number null] },
|
|
567
|
+
},
|
|
568
|
+
required: %w[key value],
|
|
569
|
+
},
|
|
570
|
+
},
|
|
571
|
+
value_field: { type: "string" },
|
|
572
|
+
pointer_class: { type: "string" },
|
|
573
|
+
flatten_arrays: { type: "boolean" },
|
|
574
|
+
sort: { type: "string" },
|
|
575
|
+
truncated: { type: "boolean" },
|
|
576
|
+
limit: { type: "integer" },
|
|
577
|
+
},
|
|
578
|
+
required: %w[class_name field operation group_count groups limit],
|
|
579
|
+
},
|
|
386
580
|
},
|
|
387
581
|
|
|
388
582
|
group_by_date: {
|
|
@@ -428,6 +622,33 @@ module Parse
|
|
|
428
622
|
},
|
|
429
623
|
required: ["class_name", "field", "interval"],
|
|
430
624
|
},
|
|
625
|
+
output_schema: {
|
|
626
|
+
type: "object",
|
|
627
|
+
properties: {
|
|
628
|
+
class_name: { type: "string" },
|
|
629
|
+
field: { type: "string" },
|
|
630
|
+
interval: { type: "string" },
|
|
631
|
+
operation: { type: "string" },
|
|
632
|
+
group_count: { type: "integer", minimum: 0 },
|
|
633
|
+
groups: {
|
|
634
|
+
type: "array",
|
|
635
|
+
items: {
|
|
636
|
+
type: "object",
|
|
637
|
+
properties: {
|
|
638
|
+
key: { type: %w[string null] },
|
|
639
|
+
value: { type: %w[number null] },
|
|
640
|
+
},
|
|
641
|
+
required: %w[key value],
|
|
642
|
+
},
|
|
643
|
+
},
|
|
644
|
+
value_field: { type: "string" },
|
|
645
|
+
timezone: { type: "string" },
|
|
646
|
+
sort: { type: "string" },
|
|
647
|
+
truncated: { type: "boolean" },
|
|
648
|
+
limit: { type: "integer" },
|
|
649
|
+
},
|
|
650
|
+
required: %w[class_name field interval operation group_count groups sort limit],
|
|
651
|
+
},
|
|
431
652
|
},
|
|
432
653
|
|
|
433
654
|
distinct: {
|
|
@@ -459,6 +680,21 @@ module Parse
|
|
|
459
680
|
},
|
|
460
681
|
required: ["class_name", "field"],
|
|
461
682
|
},
|
|
683
|
+
output_schema: {
|
|
684
|
+
type: "object",
|
|
685
|
+
properties: {
|
|
686
|
+
class_name: { type: "string" },
|
|
687
|
+
field: { type: "string" },
|
|
688
|
+
count: { type: "integer", minimum: 0 },
|
|
689
|
+
values: { type: "array",
|
|
690
|
+
items: { type: %w[string number boolean null] } },
|
|
691
|
+
pointer_class: { type: "string" },
|
|
692
|
+
sort: { type: "string" },
|
|
693
|
+
truncated: { type: "boolean" },
|
|
694
|
+
limit: { type: "integer" },
|
|
695
|
+
},
|
|
696
|
+
required: %w[class_name field count values limit],
|
|
697
|
+
},
|
|
462
698
|
},
|
|
463
699
|
|
|
464
700
|
export_data: {
|
|
@@ -687,6 +923,13 @@ module Parse
|
|
|
687
923
|
# @param permission [Symbol] :readonly, :write, or :admin (required)
|
|
688
924
|
# @param timeout [Integer] seconds before ToolTimeoutError (default: 30)
|
|
689
925
|
# @param handler [Proc] lambda(agent, **args) -> Hash (required)
|
|
926
|
+
# @param client_safe [Boolean] when +true+, the tool is dispatchable
|
|
927
|
+
# from a client-mode agent (one whose client has no master_key).
|
|
928
|
+
# Default +false+ — registered tools are master-key-only unless
|
|
929
|
+
# the author explicitly declares them safe for session-token
|
|
930
|
+
# contexts. The handler is responsible for routing through
|
|
931
|
+
# +agent.client+ with +agent.session_token+ rather than touching
|
|
932
|
+
# the master key directly.
|
|
690
933
|
# @raise [ArgumentError] when required kwargs are missing or permission is invalid
|
|
691
934
|
#
|
|
692
935
|
# @note SECURITY: Registered tool handlers run as trusted code inside the
|
|
@@ -709,7 +952,8 @@ module Parse
|
|
|
709
952
|
# register at boot from code you control; never accept registrations
|
|
710
953
|
# from configuration files at runtime.
|
|
711
954
|
def register(name:, description:, parameters:, permission:, handler:,
|
|
712
|
-
timeout: DEFAULT_TIMEOUT, output_schema: nil, category: "custom"
|
|
955
|
+
timeout: DEFAULT_TIMEOUT, output_schema: nil, category: "custom",
|
|
956
|
+
client_safe: false)
|
|
713
957
|
unless %i[readonly write admin].include?(permission)
|
|
714
958
|
raise ArgumentError, "permission must be :readonly, :write, or :admin (got #{permission.inspect})"
|
|
715
959
|
end
|
|
@@ -761,6 +1005,7 @@ module Parse
|
|
|
761
1005
|
timeout: timeout.to_i,
|
|
762
1006
|
handler: handler,
|
|
763
1007
|
output_schema: output_schema,
|
|
1008
|
+
client_safe: client_safe == true,
|
|
764
1009
|
}
|
|
765
1010
|
end
|
|
766
1011
|
notify_subscribers
|
|
@@ -848,18 +1093,19 @@ module Parse
|
|
|
848
1093
|
TOOL_TIMEOUTS[sym] || DEFAULT_TIMEOUT
|
|
849
1094
|
end
|
|
850
1095
|
|
|
851
|
-
# Resolve the MCP outputSchema for a tool, if any.
|
|
852
|
-
# registered tools
|
|
853
|
-
# built-in
|
|
854
|
-
# whether to mirror the result data as
|
|
855
|
-
# the `tools/call` response envelope.
|
|
1096
|
+
# Resolve the MCP outputSchema for a tool, if any. Checks
|
|
1097
|
+
# registered tools first (override path), then falls through to
|
|
1098
|
+
# the built-in TOOL_DEFINITIONS table. The dispatcher uses this
|
|
1099
|
+
# to decide whether to mirror the result data as
|
|
1100
|
+
# `structuredContent` in the `tools/call` response envelope.
|
|
856
1101
|
#
|
|
857
1102
|
# @param name [Symbol, String] tool name
|
|
858
1103
|
# @return [Hash, nil] JSON Schema Hash, or nil if not declared.
|
|
859
1104
|
def output_schema_for(name)
|
|
860
1105
|
sym = name.to_sym
|
|
861
1106
|
entry = REGISTRY_MUTEX.synchronize { @registry[sym] }
|
|
862
|
-
entry && entry[:output_schema]
|
|
1107
|
+
return entry[:output_schema] if entry && entry[:output_schema]
|
|
1108
|
+
TOOL_DEFINITIONS.dig(sym, :output_schema)
|
|
863
1109
|
end
|
|
864
1110
|
|
|
865
1111
|
# Resolve the category for a tool. Registered tools always carry
|
|
@@ -876,6 +1122,33 @@ module Parse
|
|
|
876
1122
|
TOOL_DEFINITIONS.dig(sym, :category)
|
|
877
1123
|
end
|
|
878
1124
|
|
|
1125
|
+
# Whether a tool is safe to dispatch from a client-mode agent
|
|
1126
|
+
# (one whose client has no master_key). Returns true for:
|
|
1127
|
+
#
|
|
1128
|
+
# * Built-in read tools listed in CLIENT_SAFE_READ_TOOLS — these
|
|
1129
|
+
# route through session-token REST endpoints that Parse Server
|
|
1130
|
+
# natively authorizes (ACL + CLP + protectedFields).
|
|
1131
|
+
# * Built-in mutation tools listed in CLIENT_SAFE_MUTATION_TOOLS —
|
|
1132
|
+
# same REST-native authorization. The caller is responsible for
|
|
1133
|
+
# additionally checking the per-agent +allow_mutations+ gate;
|
|
1134
|
+
# this predicate reports REST-safety only.
|
|
1135
|
+
# * Custom tools registered with +client_safe: true+ — the
|
|
1136
|
+
# registering author has declared the handler safe for
|
|
1137
|
+
# client-mode dispatch.
|
|
1138
|
+
#
|
|
1139
|
+
# Anything else (call_method, aggregate, atlas_*, schema tools,
|
|
1140
|
+
# custom tools registered without the flag) returns false.
|
|
1141
|
+
#
|
|
1142
|
+
# @param name [Symbol, String] tool name
|
|
1143
|
+
# @return [Boolean]
|
|
1144
|
+
def client_safe?(name)
|
|
1145
|
+
sym = name.to_sym
|
|
1146
|
+
return true if Parse::Agent::CLIENT_SAFE_READ_TOOLS.include?(sym)
|
|
1147
|
+
return true if Parse::Agent::CLIENT_SAFE_MUTATION_TOOLS.include?(sym)
|
|
1148
|
+
entry = REGISTRY_MUTEX.synchronize { @registry[sym] }
|
|
1149
|
+
entry ? entry[:client_safe] == true : false
|
|
1150
|
+
end
|
|
1151
|
+
|
|
879
1152
|
# Returns all tool names: builtins + registered.
|
|
880
1153
|
#
|
|
881
1154
|
# @return [Array<Symbol>]
|
|
@@ -2048,7 +2321,7 @@ module Parse
|
|
|
2048
2321
|
# dotted path of their own — that's the explicit "I named exactly
|
|
2049
2322
|
# what I want" signal. It's also suppressed when no `keys:` was
|
|
2050
2323
|
# passed at all (caller chose full-row mode) and when the include is
|
|
2051
|
-
# multi-hop (`
|
|
2324
|
+
# multi-hop (`author.workspace`); auto-projection is one-hop only.
|
|
2052
2325
|
#
|
|
2053
2326
|
# Pointer-to-joined-class resolution uses the parent class's
|
|
2054
2327
|
# `references` reflection (same source `walk_pointer_path!` uses),
|
|
@@ -2087,8 +2360,8 @@ module Parse
|
|
|
2087
2360
|
h[root] << k
|
|
2088
2361
|
end
|
|
2089
2362
|
|
|
2090
|
-
# Only consider one-hop includes; multi-hop (`
|
|
2091
|
-
# the
|
|
2363
|
+
# Only consider one-hop includes; multi-hop (`author.workspace`) leaves
|
|
2364
|
+
# the author projection alone and lets the deeper hop materialize
|
|
2092
2365
|
# fully — keeps the auto-expansion bounded and avoids walking the
|
|
2093
2366
|
# full relation graph at query time.
|
|
2094
2367
|
single_hop_includes = include_arr.map(&:to_s).reject { |p| p.include?(".") }
|
|
@@ -4313,7 +4586,7 @@ module Parse
|
|
|
4313
4586
|
lines = []
|
|
4314
4587
|
lines << "| #{headers.join(" | ")} |"
|
|
4315
4588
|
lines << "| #{headers.map { "---" }.join(" | ")} |"
|
|
4316
|
-
rows.each { |r| lines << "| #{r.map { |c| c.to_s.gsub("
|
|
4589
|
+
rows.each { |r| lines << "| #{r.map { |c| c.to_s.gsub(/\r?\n/, " ").gsub(/([\\|])/, '\\\\\1') }.join(" | ")} |" }
|
|
4317
4590
|
lines.join("\n")
|
|
4318
4591
|
end
|
|
4319
4592
|
module_function :format_export_markdown
|
|
@@ -4840,7 +5113,7 @@ module Parse
|
|
|
4840
5113
|
# 2. Must be an Array.
|
|
4841
5114
|
# 3. Length must not exceed {MAX_INCLUDE_FIELDS}.
|
|
4842
5115
|
# 4. Each entry must match /\A[A-Za-z][A-Za-z0-9_.]{0,127}\z/
|
|
4843
|
-
# (allows dotted pointer paths like "author.
|
|
5116
|
+
# (allows dotted pointer paths like "author.workspace"; rejects any entry
|
|
4844
5117
|
# beginning with an underscore such as "_session_token").
|
|
4845
5118
|
#
|
|
4846
5119
|
# @param include [Array<String>, nil] the include parameter to validate.
|