Allow isolated prompt probes with JSON mode and local schema validation
This commit is contained in:
1 parent
f52af70646
commit
e8d0602ed3
4 files changed
+78
-38
No files matched your search
@@ -46,7 +46,7 @@ def gemini_schema(schema):
|
||||
return result
|
||||
|
||||
|
||||
def prepare(provider,request):
|
||||
def prepare(provider,request, *, schema_mode="native"):
|
||||
if (set(request)!={'prompt_version','messages','output_schema'} or
|
||||
not isinstance(request['prompt_version'],str) or not request['prompt_version'].strip()):
|
||||
raise LLMError('PROMPT_PROBE_REQUEST')
|
||||
@@ -55,12 +55,17 @@ def prepare(provider,request):
|
||||
any(set(m)!={'role','content'} or not isinstance(m['content'],str) or not m['content'].strip() for m in messages)):
|
||||
raise LLMError('PROMPT_PROBE_REQUEST')
|
||||
Draft202012Validator.check_schema(request['output_schema'])
|
||||
generation={'maxOutputTokens':provider.max_output_tokens,'responseMimeType':'application/json',
|
||||
'responseJsonSchema':gemini_schema(request['output_schema'])}
|
||||
if schema_mode not in {'native','prompt'}:raise LLMError('PROMPT_PROBE_SCHEMA_MODE')
|
||||
generation={'maxOutputTokens':provider.max_output_tokens,'responseMimeType':'application/json'}
|
||||
system_text=messages[0]['content']
|
||||
if schema_mode=='native':
|
||||
generation['responseJsonSchema']=gemini_schema(request['output_schema'])
|
||||
else:
|
||||
system_text += '\nOutput JSON contract (validated locally):\n'+json.dumps(request['output_schema'],ensure_ascii=False,separators=(',',':'))
|
||||
if provider.reasoning_effort is not None:generation['thinkingConfig']={'thinkingLevel':provider.reasoning_effort}
|
||||
payload={'systemInstruction':{'parts':[{'text':messages[0]['content']}]},
|
||||
payload={'systemInstruction':{'parts':[{'text':system_text}]},
|
||||
'contents':[{'role':'user','parts':[{'text':messages[1]['content']}]}],'generationConfig':generation}
|
||||
return {'id':request['prompt_version'],'prompt_characters':sum(len(m['content']) for m in messages),
|
||||
return {'id':request['prompt_version'],'prompt_characters':len(system_text)+len(messages[1]['content']),
|
||||
'payload':payload,'validation_schema':request['output_schema']}
|
||||
|
||||
|
||||
@@ -109,6 +114,7 @@ def main(argv=None):
|
||||
p.add_argument('--request',type=Path,default=DEFAULT)
|
||||
p.add_argument('--llm-config',default='config/llm.working-brief.local.toml')
|
||||
p.add_argument('--provider')
|
||||
p.add_argument('--schema-mode',choices=['native','prompt'],default='native',help='Native schema or JSON mode with the full contract once in the prompt')
|
||||
p.add_argument('--output',type=Path)
|
||||
p.add_argument('--run',action='store_true',help='Make exactly one potentially billable API call')
|
||||
args=p.parse_args(argv)
|
||||
@@ -119,13 +125,13 @@ def main(argv=None):
|
||||
if provider is None or provider.adapter!='gemini':raise LLMError('PROMPT_PROBE_PROVIDER')
|
||||
raw=args.request.read_bytes()
|
||||
if len(raw)>config.max_request_bytes:raise LLMError('LLM_REQUEST_LIMIT')
|
||||
request=json.loads(raw);case=prepare(provider,request)
|
||||
request=json.loads(raw);case=prepare(provider,request,schema_mode=args.schema_mode)
|
||||
if len(json.dumps(case['payload'],ensure_ascii=False).encode('utf-8'))>config.max_request_bytes:raise LLMError('LLM_REQUEST_LIMIT')
|
||||
metadata={'request_sha256':hashlib.sha256(raw).hexdigest(),'provider':provider.id,'model':provider.model,
|
||||
'reasoning_effort':provider.reasoning_effort,'max_output_tokens':provider.max_output_tokens,
|
||||
'timeout_seconds':provider.timeout_seconds,'explicit_cache':False,'research_queries_executed':0,
|
||||
'wire_schema_sha256':hashlib.sha256(json.dumps(case['payload']['generationConfig']['responseJsonSchema'],sort_keys=True,separators=(',',':')).encode()).hexdigest(),
|
||||
'schema_transport':'gemini_subset_v1_local_full_validation'}
|
||||
'wire_schema_sha256':hashlib.sha256(json.dumps(case['payload']['generationConfig'].get('responseJsonSchema'),sort_keys=True,separators=(',',':')).encode()).hexdigest(),
|
||||
'schema_transport':'gemini_subset_v1_local_full_validation' if args.schema_mode=='native' else 'json_mode_schema_once_in_prompt_local_full_validation'}
|
||||
if not args.run:
|
||||
print(json.dumps({'status':'PREPARED','network_used':False,**metadata,
|
||||
'message_characters':case['prompt_characters']}));return 0
|
||||
|
||||
Reference in new issue
Block a user