llm-testrunner-components 1.2.1 → 1.2.3
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.
- package/dist/cjs/app-chips_4.cjs.entry.js +5 -2
- package/dist/cjs/app-chips_4.cjs.entry.js.map +1 -1
- package/dist/cjs/index.cjs.js +206 -45
- package/dist/cjs/index.cjs.js.map +1 -1
- package/dist/cjs/llm-testrunner.cjs.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/llm-test-runner/llm-test-runner.js +111 -29
- package/dist/collection/components/llm-test-runner/llm-test-runner.js.map +1 -1
- package/dist/collection/components/llm-test-runner/test-cases/expected-outcome-renderer.js +37 -4
- package/dist/collection/components/llm-test-runner/test-cases/expected-outcome-renderer.js.map +1 -1
- package/dist/collection/components/llm-test-runner/test-cases/llm-test-case-row.js +2 -2
- package/dist/collection/components/llm-test-runner/test-cases/llm-test-case-row.js.map +1 -1
- package/dist/collection/components/llm-test-runner/test-cases/llm-test-cases.js +2 -2
- package/dist/collection/components/llm-test-runner/test-cases/llm-test-cases.js.map +1 -1
- package/dist/collection/lib/evaluation/evaluation-service.js +14 -7
- package/dist/collection/lib/evaluation/evaluation-service.js.map +1 -1
- package/dist/collection/lib/form/components/app-textarea.css +17 -0
- package/dist/collection/lib/form/components/app-textarea.js +4 -1
- package/dist/collection/lib/form/components/app-textarea.js.map +1 -1
- package/dist/collection/lib/test-cases/dynamic-expected-outcome-resolver.js +44 -0
- package/dist/collection/lib/test-cases/dynamic-expected-outcome-resolver.js.map +1 -0
- package/dist/collection/lib/test-cases/test-case-factory.js +1 -1
- package/dist/collection/lib/test-cases/test-case-factory.js.map +1 -1
- package/dist/collection/lib/test-cases/test-case-mutations.js +35 -0
- package/dist/collection/lib/test-cases/test-case-mutations.js.map +1 -1
- package/dist/collection/schemas/expected-outcome.js +15 -1
- package/dist/collection/schemas/expected-outcome.js.map +1 -1
- package/dist/collection/schemas/test-case.js.map +1 -1
- package/dist/collection/types/expected-outcome.js.map +1 -1
- package/dist/collection/types/llm-test-runner.js.map +1 -1
- package/dist/components/app-textarea.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/llm-test-runner.js +1 -1
- package/dist/components/{p-JPMPoOC8.js → p-BcygfrMf.js} +3 -3
- package/dist/components/p-BcygfrMf.js.map +1 -0
- package/dist/components/p-CVtKFBJl.js +2 -0
- package/dist/components/p-CVtKFBJl.js.map +1 -0
- package/dist/esm/app-chips_4.entry.js +5 -2
- package/dist/esm/app-chips_4.entry.js.map +1 -1
- package/dist/esm/index.js +206 -45
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/llm-testrunner.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/llm-testrunner/index.esm.js +2 -2
- package/dist/llm-testrunner/index.esm.js.map +1 -1
- package/dist/llm-testrunner/llm-testrunner.esm.js +1 -1
- package/dist/llm-testrunner/{p-2cc09217.entry.js → p-5df053b4.entry.js} +2 -2
- package/dist/llm-testrunner/{p-2cc09217.entry.js.map → p-5df053b4.entry.js.map} +1 -1
- package/dist/types/components/llm-test-runner/llm-test-runner.d.ts +6 -0
- package/dist/types/components/llm-test-runner/test-cases/expected-outcome-renderer.d.ts +1 -0
- package/dist/types/components/llm-test-runner/test-cases/llm-test-case-row.d.ts +1 -0
- package/dist/types/components/llm-test-runner/test-cases/llm-test-cases.d.ts +1 -0
- package/dist/types/components.d.ts +7 -0
- package/dist/types/lib/test-cases/dynamic-expected-outcome-resolver.d.ts +7 -0
- package/dist/types/lib/test-cases/test-case-mutations.d.ts +9 -1
- package/dist/types/schemas/expected-outcome.d.ts +16 -1
- package/dist/types/schemas/test-case.d.ts +17 -2
- package/dist/types/types/expected-outcome.d.ts +1 -1
- package/dist/types/types/llm-test-runner.d.ts +1 -1
- package/package.json +5 -1
- package/dist/components/p-BZrzx5jG.js +0 -2
- package/dist/components/p-BZrzx5jG.js.map +0 -1
- package/dist/components/p-JPMPoOC8.js.map +0 -1
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{p as e,H as a,e as r,h as t,t as o}from"./p-D9BrlHdP.js";const n=()=>`.textarea-wrapper{margin-bottom:var(--spacing-4)}.textarea-label{display:block;margin-bottom:var(--spacing-2);font-weight:var(--font-weight-medium);color:var(--foreground);font-size:var(--font-size-sm)}.textarea-element{width:95%;box-sizing:border-box;padding:var(--spacing-3);border:2px solid var(--input);border-radius:var(--radius);font-size:var(--font-size-sm);resize:vertical;outline:none;transition:border-color 0.2s ease;font-family:inherit;background:var(--background);color:var(--foreground)}.textarea-element:focus{border-color:var(--ring);box-shadow:0 0 0 3px rgba(59, 130, 246, 0.1)}.textarea-wrapper--read-only .textarea-label{color:var(--muted-foreground)}.textarea-element:read-only{background:var(--muted);color:var(--muted-foreground);border-color:var(--border);cursor:not-allowed;resize:none}.textarea-element:read-only:focus{border-color:var(--border);box-shadow:none}.help-text{margin-top:var(--spacing-1);font-size:var(--font-size-xs);color:var(--muted-foreground, #6b7280);line-height:1.4}`;const s=e(class e extends a{constructor(e){super();if(e!==false){this.__registerHost()}this.__attachShadow();this.valueChange=r(this,"valueChange")}value;config;valueChange;handleChange=e=>{const a=e.target;this.valueChange.emit({value:a.value})};render(){const e=this.config;const a={placeholder:e.placeholder,required:e.required,disabled:e.disabled,readOnly:e.readOnly,rows:e.rows,id:e.name,name:e.name,autocomplete:e.autocomplete};return t("div",{key:"29bbcd954df6d18e968f6b2670224fda6f03a9f2",class:{"textarea-wrapper":true,"textarea-wrapper--read-only":!!e.readOnly}},e.label&&t("label",{key:"d95d3cbf01ce66c5bd074ede2eb1f87a0c98f3e4",class:"textarea-label",htmlFor:e.name},e.label),t("textarea",{key:"faeb28c35a543213d9c5847e93779f957e367ff0",...a,class:"textarea-element",value:this.value,onInput:this.handleChange}),e.helpText&&t("p",{key:"558abfe03f7107352a6d40aea78a35b304bc11a6",class:"help-text"},e.helpText))}static get style(){return n()}},[513,"app-textarea",{value:[1],config:[16]}]);function l(){if(typeof customElements==="undefined"){return}const e=["app-textarea"];e.forEach((e=>{switch(e){case"app-textarea":if(!customElements.get(o(e))){customElements.define(o(e),s)}break}}))}export{s as A,l as d};
|
|
2
|
+
//# sourceMappingURL=p-CVtKFBJl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["appTextareaCss","AppTextarea","__stencil_proxyCustomElement","HTMLElement","value","config","valueChange","handleChange","e","target","this","emit","render","c","allowedAttrs","placeholder","required","disabled","readOnly","rows","id","name","autocomplete","h","key","class","label","htmlFor","onInput","helpText"],"sources":["src/lib/form/components/app-textarea.css?tag=app-textarea&encapsulation=shadow","src/lib/form/components/app-textarea.tsx"],"sourcesContent":[".textarea-wrapper {\n margin-bottom: var(--spacing-4);\n}\n\n.textarea-label {\n display: block;\n margin-bottom: var(--spacing-2);\n font-weight: var(--font-weight-medium);\n color: var(--foreground);\n font-size: var(--font-size-sm);\n}\n\n.textarea-element {\n width: 95%;\n box-sizing: border-box;\n padding: var(--spacing-3);\n border: 2px solid var(--input);\n border-radius: var(--radius);\n font-size: var(--font-size-sm);\n resize: vertical;\n outline: none;\n transition: border-color 0.2s ease;\n font-family: inherit;\n background: var(--background);\n color: var(--foreground);\n}\n\n.textarea-element:focus {\n border-color: var(--ring);\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.textarea-wrapper--read-only .textarea-label {\n color: var(--muted-foreground);\n}\n\n.textarea-element:read-only {\n background: var(--muted);\n color: var(--muted-foreground);\n border-color: var(--border);\n cursor: not-allowed;\n resize: none;\n}\n\n.textarea-element:read-only:focus {\n border-color: var(--border);\n box-shadow: none;\n}\n\n.help-text {\n margin-top: var(--spacing-1);\n font-size: var(--font-size-xs);\n color: var(--muted-foreground, #6b7280);\n line-height: 1.4;\n}\n","import { Component, Event, EventEmitter, Prop, h } from '@stencil/core';\nimport { TextAreaConfig } from '../schema';\n\n@Component({\n tag: 'app-textarea',\n styleUrl: 'app-textarea.css',\n shadow: true,\n})\nexport class AppTextarea {\n @Prop() value: string;\n @Prop() config: TextAreaConfig;\n\n @Event() valueChange: EventEmitter<{ value: string }>;\n\n private handleChange = (e: Event) => {\n const target = e.target as HTMLTextAreaElement;\n\n this.valueChange.emit({\n value: target.value,\n });\n };\n\n render() {\n const c = this.config;\n\n const allowedAttrs = {\n placeholder: c.placeholder,\n required: c.required,\n disabled: c.disabled,\n readOnly: c.readOnly,\n rows: c.rows,\n id: c.name,\n name: c.name,\n autocomplete: c.autocomplete,\n };\n\n return (\n <div\n class={{\n 'textarea-wrapper': true,\n 'textarea-wrapper--read-only': !!c.readOnly,\n }}\n >\n {c.label && (\n <label class=\"textarea-label\" htmlFor={c.name}>\n {c.label}\n </label>\n )}\n\n <textarea\n {...allowedAttrs}\n class=\"textarea-element\"\n value={this.value}\n onInput={this.handleChange}\n ></textarea>\n\n {c.helpText && <p class=\"help-text\">{c.helpText}</p>}\n </div>\n );\n }\n}\n"],"mappings":"gEAAA,MAAMA,EAAiB,IAAM,s/B,MCQhBC,EAAWC,EAAA,MAAAD,UAAAE,E,wHACdC,MACAC,OAECC,YAEDC,aAAgBC,IACtB,MAAMC,EAASD,EAAEC,OAEjBC,KAAKJ,YAAYK,KAAK,CACpBP,MAAOK,EAAOL,OACd,EAGJ,MAAAQ,GACE,MAAMC,EAAIH,KAAKL,OAEf,MAAMS,EAAe,CACnBC,YAAaF,EAAEE,YACfC,SAAUH,EAAEG,SACZC,SAAUJ,EAAEI,SACZC,SAAUL,EAAEK,SACZC,KAAMN,EAAEM,KACRC,GAAIP,EAAEQ,KACNA,KAAMR,EAAEQ,KACRC,aAAcT,EAAES,cAGlB,OACEC,EAAA,OAAAC,IAAA,2CACEC,MAAO,CACL,mBAAoB,KACpB,gCAAiCZ,EAAEK,WAGpCL,EAAEa,OACDH,EAAA,SAAAC,IAAA,2CAAOC,MAAM,iBAAiBE,QAASd,EAAEQ,MACtCR,EAAEa,OAIPH,EAAA,YAAAC,IAAA,8CACMV,EACJW,MAAM,mBACNrB,MAAOM,KAAKN,MACZwB,QAASlB,KAAKH,eAGfM,EAAEgB,UAAYN,EAAA,KAAAC,IAAA,2CAAGC,MAAM,aAAaZ,EAAEgB,U","ignoreList":[]}
|
|
@@ -88,7 +88,7 @@ const AppSelect = class {
|
|
|
88
88
|
};
|
|
89
89
|
AppSelect.style = appSelectCss();
|
|
90
90
|
|
|
91
|
-
const appTextareaCss = () => `.textarea-wrapper{margin-bottom:var(--spacing-4)}.textarea-label{display:block;margin-bottom:var(--spacing-2);font-weight:var(--font-weight-medium);color:var(--foreground);font-size:var(--font-size-sm)}.textarea-element{width:95%;box-sizing:border-box;padding:var(--spacing-3);border:2px solid var(--input);border-radius:var(--radius);font-size:var(--font-size-sm);resize:vertical;outline:none;transition:border-color 0.2s ease;font-family:inherit;background:var(--background);color:var(--foreground)}.textarea-element:focus{border-color:var(--ring);box-shadow:0 0 0 3px rgba(59, 130, 246, 0.1)}.help-text{margin-top:var(--spacing-1);font-size:var(--font-size-xs);color:var(--muted-foreground, #6b7280);line-height:1.4}`;
|
|
91
|
+
const appTextareaCss = () => `.textarea-wrapper{margin-bottom:var(--spacing-4)}.textarea-label{display:block;margin-bottom:var(--spacing-2);font-weight:var(--font-weight-medium);color:var(--foreground);font-size:var(--font-size-sm)}.textarea-element{width:95%;box-sizing:border-box;padding:var(--spacing-3);border:2px solid var(--input);border-radius:var(--radius);font-size:var(--font-size-sm);resize:vertical;outline:none;transition:border-color 0.2s ease;font-family:inherit;background:var(--background);color:var(--foreground)}.textarea-element:focus{border-color:var(--ring);box-shadow:0 0 0 3px rgba(59, 130, 246, 0.1)}.textarea-wrapper--read-only .textarea-label{color:var(--muted-foreground)}.textarea-element:read-only{background:var(--muted);color:var(--muted-foreground);border-color:var(--border);cursor:not-allowed;resize:none}.textarea-element:read-only:focus{border-color:var(--border);box-shadow:none}.help-text{margin-top:var(--spacing-1);font-size:var(--font-size-xs);color:var(--muted-foreground, #6b7280);line-height:1.4}`;
|
|
92
92
|
|
|
93
93
|
const AppTextarea = class {
|
|
94
94
|
constructor(hostRef) {
|
|
@@ -116,7 +116,10 @@ const AppTextarea = class {
|
|
|
116
116
|
name: c.name,
|
|
117
117
|
autocomplete: c.autocomplete,
|
|
118
118
|
};
|
|
119
|
-
return (h("div", { key: '
|
|
119
|
+
return (h("div", { key: '29bbcd954df6d18e968f6b2670224fda6f03a9f2', class: {
|
|
120
|
+
'textarea-wrapper': true,
|
|
121
|
+
'textarea-wrapper--read-only': !!c.readOnly,
|
|
122
|
+
} }, c.label && (h("label", { key: 'd95d3cbf01ce66c5bd074ede2eb1f87a0c98f3e4', class: "textarea-label", htmlFor: c.name }, c.label)), h("textarea", { key: 'faeb28c35a543213d9c5847e93779f957e367ff0', ...allowedAttrs, class: "textarea-element", value: this.value, onInput: this.handleChange }), c.helpText && h("p", { key: '558abfe03f7107352a6d40aea78a35b304bc11a6', class: "help-text" }, c.helpText)));
|
|
120
123
|
}
|
|
121
124
|
};
|
|
122
125
|
AppTextarea.style = appTextareaCss();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"file":"app-chips_4.entry.js","mappings":"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","names":[],"sources":["src/lib/form/components/app-chips.css?tag=app-chips&encapsulation=shadow","src/lib/form/components/app-chips.tsx","src/lib/form/components/app-select.css?tag=app-select&encapsulation=shadow","src/lib/form/components/app-select.tsx","src/lib/form/components/app-textarea.css?tag=app-textarea&encapsulation=shadow","src/lib/form/components/app-textarea.tsx"],"sourcesContent":[".app-chips {\n margin-bottom: var(--spacing-4);\n}\n\n.app-chips__label {\n display: block;\n margin-bottom: var(--spacing-2);\n font-weight: var(--font-weight-medium);\n color: var(--foreground);\n font-size: var(--font-size-sm);\n}\n\n.app-chips__container {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-2);\n align-items: center;\n}\n\n.app-chips__chip {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-2);\n padding: var(--spacing-1) var(--spacing-2);\n font-size: var(--font-size-xs);\n font-weight: var(--font-weight-medium);\n border-radius: var(--radius-md);\n background: var(--accent);\n border: var(--border-width) solid var(--border);\n}\n\n/* Keyword-style chip override (non-URL chips) */\n.app-chips__chip:not(:has(a)) {\n background: var(--info);\n color: var(--info-foreground);\n border: none;\n border-radius: var(--radius-2xl);\n}\n\n.app-chips__link {\n color: var(--info);\n text-decoration: none;\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.app-chips__link:hover {\n text-decoration: underline;\n}\n\n.app-chips__remove {\n background: none;\n border: none;\n cursor: pointer;\n font-size: var(--font-size-xs);\n padding: 0;\n width: var(--spacing-4);\n height: var(--spacing-4);\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--radius-full);\n color: var(--muted-foreground);\n opacity: var(--opacity-muted);\n}\n\n.app-chips__chip:not(:has(a)) .app-chips__remove {\n color: var(--info-foreground);\n opacity: var(--opacity-hover);\n}\n\n.app-chips__remove:hover {\n opacity: 1;\n background: var(--muted);\n}\n\n.app-chips__chip:not(:has(a)) .app-chips__remove:hover {\n background: rgba(255, 255, 255, 0.2);\n}\n\n.app-chips__input {\n border: var(--border-width) solid var(--input);\n border-radius: var(--radius-md);\n padding: var(--spacing-2);\n font-size: var(--font-size-xs);\n outline: none;\n min-width: 120px;\n background: var(--background);\n color: var(--foreground);\n}\n\n.app-chips__input:focus {\n border-color: var(--ring);\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\n}\n","import { Component, Prop, h, Event, EventEmitter } from '@stencil/core';\nimport { ChipsConfig } from '../schema';\n\n@Component({\n tag: 'app-chips',\n styleUrl: 'app-chips.css',\n shadow: true,\n})\nexport class AppChips {\n @Prop() value: string[] = [];\n @Prop() config: ChipsConfig;\n\n @Event() addChip: EventEmitter<{ value: string }>;\n\n @Event() removeChip: EventEmitter<{ value: string }>;\n\n private emitAddChip(val: string) {\n this.addChip.emit({\n value: val,\n });\n }\n\n private emitRemoveChip(value: string) {\n this.removeChip.emit({\n value,\n });\n }\n\n private hasDuplicateChip(value: string): boolean {\n const normalized = value.trim().toLowerCase();\n return this.value.some(chip => chip.trim().toLowerCase() === normalized);\n }\n\n render() {\n const c = this.config;\n\n const allowedAttrs = {\n placeholder: c.placeholder,\n required: c.required,\n disabled: c.disabled,\n readOnly: c.readOnly,\n id: c.name,\n name: c.name,\n autocomplete: c.autocomplete,\n };\n\n return (\n <div class=\"app-chips\">\n {c.label && (\n <label class=\"app-chips__label\" htmlFor={c.name}>\n {c.label}\n </label>\n )}\n\n <div class=\"app-chips__container\">\n {this.value.map((chip) => (\n <span class=\"app-chips__chip\" key={chip}>\n {c.type === 'url' ? (\n <a\n href={chip}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"app-chips__link\"\n >\n {chip}\n </a>\n ) : (\n chip\n )}\n\n <button\n class=\"app-chips__remove\"\n type=\"button\"\n onClick={() => this.emitRemoveChip(chip)}\n >\n ×\n </button>\n </span>\n ))}\n\n <input\n class=\"app-chips__input\"\n type={c.type || 'text'}\n {...allowedAttrs}\n onKeyDown={(e: KeyboardEvent) => {\n if (e.key === 'Enter') {\n const input = e.target as HTMLInputElement;\n const val = input.value.trim();\n if (!val) return;\n if (this.hasDuplicateChip(val)) {\n input.value = '';\n return;\n }\n\n this.emitAddChip(val);\n input.value = '';\n }\n }}\n />\n </div>\n </div>\n );\n }\n}\n",".app-select {\n margin-bottom: var(--spacing-4);\n}\n\n.app-select__label {\n display: block;\n margin-bottom: var(--spacing-2);\n font-weight: var(--font-weight-medium);\n color: var(--foreground);\n font-size: var(--font-size-sm);\n}\n\n.app-select__select {\n border: var(--border-width) solid var(--input);\n border-radius: var(--radius-md);\n font-size: var(--font-size-sm);\n font-weight: var(--font-weight-medium);\n padding: var(--spacing-1) var(--spacing-2);\n outline: none;\n background: var(--background);\n width: 145px;\n color: var(--foreground);\n}\n\n.app-select__select:focus {\n border-color: var(--ring);\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\n}\n","import { Component, Event, EventEmitter, Prop, h } from '@stencil/core';\nimport { SelectConfig } from '../schema';\n\n@Component({\n tag: 'app-select',\n styleUrl: 'app-select.css',\n shadow: true,\n})\nexport class AppSelect {\n @Prop() value: string;\n @Prop() config: SelectConfig;\n @Event() valueChange: EventEmitter<{ value: string }>;\n\n render() {\n const c = this.config;\n const allowedAttrs = {\n id: c.name,\n name: c.name,\n disabled: c.disabled,\n required: c.required,\n readOnly: c.readOnly,\n placeholder: c.placeholder,\n autocomplete: c.autocomplete,\n };\n return (\n <div class=\"app-select\">\n {c.label && (\n <label class=\"app-select__label\" htmlFor={c.name}>\n {c.label}\n </label>\n )}\n\n <div>\n <select\n {...allowedAttrs}\n class=\"app-select__select\"\n onInput={(e: Event) => {\n const raw = (e.target as HTMLSelectElement).value;\n const matched = c.optionList.find(opt => String(opt) === raw);\n this.valueChange.emit({\n value: matched !== undefined ? matched : raw,\n });\n }}\n >\n {c.optionList?.map(option => (\n <option\n value={String(option)}\n key={String(option)}\n selected={this.value === option}\n >\n {String(option)}\n </option>\n ))}\n </select>\n </div>\n </div>\n );\n }\n}\n",".textarea-wrapper {\n margin-bottom: var(--spacing-4);\n}\n\n.textarea-label {\n display: block;\n margin-bottom: var(--spacing-2);\n font-weight: var(--font-weight-medium);\n color: var(--foreground);\n font-size: var(--font-size-sm);\n}\n\n.textarea-element {\n width: 95%;\n box-sizing: border-box;\n padding: var(--spacing-3);\n border: 2px solid var(--input);\n border-radius: var(--radius);\n font-size: var(--font-size-sm);\n resize: vertical;\n outline: none;\n transition: border-color 0.2s ease;\n font-family: inherit;\n background: var(--background);\n color: var(--foreground);\n}\n\n.textarea-element:focus {\n border-color: var(--ring);\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.help-text {\n margin-top: var(--spacing-1);\n font-size: var(--font-size-xs);\n color: var(--muted-foreground, #6b7280);\n line-height: 1.4;\n}\n","import { Component, Event, EventEmitter, Prop, h } from '@stencil/core';\nimport { TextAreaConfig } from '../schema';\n\n@Component({\n tag: 'app-textarea',\n styleUrl: 'app-textarea.css',\n shadow: true,\n})\nexport class AppTextarea {\n @Prop() value: string;\n @Prop() config: TextAreaConfig;\n\n @Event() valueChange: EventEmitter<{ value: string }>;\n\n private handleChange = (e: Event) => {\n const target = e.target as HTMLTextAreaElement;\n\n this.valueChange.emit({\n value: target.value,\n });\n };\n\n render() {\n const c = this.config;\n\n const allowedAttrs = {\n placeholder: c.placeholder,\n required: c.required,\n disabled: c.disabled,\n readOnly: c.readOnly,\n rows: c.rows,\n id: c.name,\n name: c.name,\n autocomplete: c.autocomplete,\n };\n\n return (\n <div class=\"textarea-wrapper\">\n {c.label && (\n <label class=\"textarea-label\" htmlFor={c.name}>\n {c.label}\n </label>\n )}\n\n <textarea\n {...allowedAttrs}\n class=\"textarea-element\"\n value={this.value}\n onInput={this.handleChange}\n ></textarea>\n\n {c.helpText && <p class=\"help-text\">{c.helpText}</p>}\n </div>\n );\n }\n}\n"],"version":3}
|
|
1
|
+
{"file":"app-chips_4.entry.js","mappings":"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","names":[],"sources":["src/lib/form/components/app-chips.css?tag=app-chips&encapsulation=shadow","src/lib/form/components/app-chips.tsx","src/lib/form/components/app-select.css?tag=app-select&encapsulation=shadow","src/lib/form/components/app-select.tsx","src/lib/form/components/app-textarea.css?tag=app-textarea&encapsulation=shadow","src/lib/form/components/app-textarea.tsx"],"sourcesContent":[".app-chips {\n margin-bottom: var(--spacing-4);\n}\n\n.app-chips__label {\n display: block;\n margin-bottom: var(--spacing-2);\n font-weight: var(--font-weight-medium);\n color: var(--foreground);\n font-size: var(--font-size-sm);\n}\n\n.app-chips__container {\n display: flex;\n flex-wrap: wrap;\n gap: var(--spacing-2);\n align-items: center;\n}\n\n.app-chips__chip {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-2);\n padding: var(--spacing-1) var(--spacing-2);\n font-size: var(--font-size-xs);\n font-weight: var(--font-weight-medium);\n border-radius: var(--radius-md);\n background: var(--accent);\n border: var(--border-width) solid var(--border);\n}\n\n/* Keyword-style chip override (non-URL chips) */\n.app-chips__chip:not(:has(a)) {\n background: var(--info);\n color: var(--info-foreground);\n border: none;\n border-radius: var(--radius-2xl);\n}\n\n.app-chips__link {\n color: var(--info);\n text-decoration: none;\n max-width: 200px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.app-chips__link:hover {\n text-decoration: underline;\n}\n\n.app-chips__remove {\n background: none;\n border: none;\n cursor: pointer;\n font-size: var(--font-size-xs);\n padding: 0;\n width: var(--spacing-4);\n height: var(--spacing-4);\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--radius-full);\n color: var(--muted-foreground);\n opacity: var(--opacity-muted);\n}\n\n.app-chips__chip:not(:has(a)) .app-chips__remove {\n color: var(--info-foreground);\n opacity: var(--opacity-hover);\n}\n\n.app-chips__remove:hover {\n opacity: 1;\n background: var(--muted);\n}\n\n.app-chips__chip:not(:has(a)) .app-chips__remove:hover {\n background: rgba(255, 255, 255, 0.2);\n}\n\n.app-chips__input {\n border: var(--border-width) solid var(--input);\n border-radius: var(--radius-md);\n padding: var(--spacing-2);\n font-size: var(--font-size-xs);\n outline: none;\n min-width: 120px;\n background: var(--background);\n color: var(--foreground);\n}\n\n.app-chips__input:focus {\n border-color: var(--ring);\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\n}\n","import { Component, Prop, h, Event, EventEmitter } from '@stencil/core';\nimport { ChipsConfig } from '../schema';\n\n@Component({\n tag: 'app-chips',\n styleUrl: 'app-chips.css',\n shadow: true,\n})\nexport class AppChips {\n @Prop() value: string[] = [];\n @Prop() config: ChipsConfig;\n\n @Event() addChip: EventEmitter<{ value: string }>;\n\n @Event() removeChip: EventEmitter<{ value: string }>;\n\n private emitAddChip(val: string) {\n this.addChip.emit({\n value: val,\n });\n }\n\n private emitRemoveChip(value: string) {\n this.removeChip.emit({\n value,\n });\n }\n\n private hasDuplicateChip(value: string): boolean {\n const normalized = value.trim().toLowerCase();\n return this.value.some(chip => chip.trim().toLowerCase() === normalized);\n }\n\n render() {\n const c = this.config;\n\n const allowedAttrs = {\n placeholder: c.placeholder,\n required: c.required,\n disabled: c.disabled,\n readOnly: c.readOnly,\n id: c.name,\n name: c.name,\n autocomplete: c.autocomplete,\n };\n\n return (\n <div class=\"app-chips\">\n {c.label && (\n <label class=\"app-chips__label\" htmlFor={c.name}>\n {c.label}\n </label>\n )}\n\n <div class=\"app-chips__container\">\n {this.value.map((chip) => (\n <span class=\"app-chips__chip\" key={chip}>\n {c.type === 'url' ? (\n <a\n href={chip}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"app-chips__link\"\n >\n {chip}\n </a>\n ) : (\n chip\n )}\n\n <button\n class=\"app-chips__remove\"\n type=\"button\"\n onClick={() => this.emitRemoveChip(chip)}\n >\n ×\n </button>\n </span>\n ))}\n\n <input\n class=\"app-chips__input\"\n type={c.type || 'text'}\n {...allowedAttrs}\n onKeyDown={(e: KeyboardEvent) => {\n if (e.key === 'Enter') {\n const input = e.target as HTMLInputElement;\n const val = input.value.trim();\n if (!val) return;\n if (this.hasDuplicateChip(val)) {\n input.value = '';\n return;\n }\n\n this.emitAddChip(val);\n input.value = '';\n }\n }}\n />\n </div>\n </div>\n );\n }\n}\n",".app-select {\n margin-bottom: var(--spacing-4);\n}\n\n.app-select__label {\n display: block;\n margin-bottom: var(--spacing-2);\n font-weight: var(--font-weight-medium);\n color: var(--foreground);\n font-size: var(--font-size-sm);\n}\n\n.app-select__select {\n border: var(--border-width) solid var(--input);\n border-radius: var(--radius-md);\n font-size: var(--font-size-sm);\n font-weight: var(--font-weight-medium);\n padding: var(--spacing-1) var(--spacing-2);\n outline: none;\n background: var(--background);\n width: 145px;\n color: var(--foreground);\n}\n\n.app-select__select:focus {\n border-color: var(--ring);\n box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.1);\n}\n","import { Component, Event, EventEmitter, Prop, h } from '@stencil/core';\nimport { SelectConfig } from '../schema';\n\n@Component({\n tag: 'app-select',\n styleUrl: 'app-select.css',\n shadow: true,\n})\nexport class AppSelect {\n @Prop() value: string;\n @Prop() config: SelectConfig;\n @Event() valueChange: EventEmitter<{ value: string }>;\n\n render() {\n const c = this.config;\n const allowedAttrs = {\n id: c.name,\n name: c.name,\n disabled: c.disabled,\n required: c.required,\n readOnly: c.readOnly,\n placeholder: c.placeholder,\n autocomplete: c.autocomplete,\n };\n return (\n <div class=\"app-select\">\n {c.label && (\n <label class=\"app-select__label\" htmlFor={c.name}>\n {c.label}\n </label>\n )}\n\n <div>\n <select\n {...allowedAttrs}\n class=\"app-select__select\"\n onInput={(e: Event) => {\n const raw = (e.target as HTMLSelectElement).value;\n const matched = c.optionList.find(opt => String(opt) === raw);\n this.valueChange.emit({\n value: matched !== undefined ? matched : raw,\n });\n }}\n >\n {c.optionList?.map(option => (\n <option\n value={String(option)}\n key={String(option)}\n selected={this.value === option}\n >\n {String(option)}\n </option>\n ))}\n </select>\n </div>\n </div>\n );\n }\n}\n",".textarea-wrapper {\n margin-bottom: var(--spacing-4);\n}\n\n.textarea-label {\n display: block;\n margin-bottom: var(--spacing-2);\n font-weight: var(--font-weight-medium);\n color: var(--foreground);\n font-size: var(--font-size-sm);\n}\n\n.textarea-element {\n width: 95%;\n box-sizing: border-box;\n padding: var(--spacing-3);\n border: 2px solid var(--input);\n border-radius: var(--radius);\n font-size: var(--font-size-sm);\n resize: vertical;\n outline: none;\n transition: border-color 0.2s ease;\n font-family: inherit;\n background: var(--background);\n color: var(--foreground);\n}\n\n.textarea-element:focus {\n border-color: var(--ring);\n box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);\n}\n\n.textarea-wrapper--read-only .textarea-label {\n color: var(--muted-foreground);\n}\n\n.textarea-element:read-only {\n background: var(--muted);\n color: var(--muted-foreground);\n border-color: var(--border);\n cursor: not-allowed;\n resize: none;\n}\n\n.textarea-element:read-only:focus {\n border-color: var(--border);\n box-shadow: none;\n}\n\n.help-text {\n margin-top: var(--spacing-1);\n font-size: var(--font-size-xs);\n color: var(--muted-foreground, #6b7280);\n line-height: 1.4;\n}\n","import { Component, Event, EventEmitter, Prop, h } from '@stencil/core';\nimport { TextAreaConfig } from '../schema';\n\n@Component({\n tag: 'app-textarea',\n styleUrl: 'app-textarea.css',\n shadow: true,\n})\nexport class AppTextarea {\n @Prop() value: string;\n @Prop() config: TextAreaConfig;\n\n @Event() valueChange: EventEmitter<{ value: string }>;\n\n private handleChange = (e: Event) => {\n const target = e.target as HTMLTextAreaElement;\n\n this.valueChange.emit({\n value: target.value,\n });\n };\n\n render() {\n const c = this.config;\n\n const allowedAttrs = {\n placeholder: c.placeholder,\n required: c.required,\n disabled: c.disabled,\n readOnly: c.readOnly,\n rows: c.rows,\n id: c.name,\n name: c.name,\n autocomplete: c.autocomplete,\n };\n\n return (\n <div\n class={{\n 'textarea-wrapper': true,\n 'textarea-wrapper--read-only': !!c.readOnly,\n }}\n >\n {c.label && (\n <label class=\"textarea-label\" htmlFor={c.name}>\n {c.label}\n </label>\n )}\n\n <textarea\n {...allowedAttrs}\n class=\"textarea-element\"\n value={this.value}\n onInput={this.handleChange}\n ></textarea>\n\n {c.helpText && <p class=\"help-text\">{c.helpText}</p>}\n </div>\n );\n }\n}\n"],"version":3}
|
package/dist/esm/index.js
CHANGED
|
@@ -335,7 +335,7 @@ function createExpectedOutcomeFieldFromSchema(schemaField) {
|
|
|
335
335
|
type: 'select',
|
|
336
336
|
label: schemaField.label,
|
|
337
337
|
placeholder: schemaField.placeholder,
|
|
338
|
-
value:
|
|
338
|
+
value: schemaField.options[0],
|
|
339
339
|
options: schemaField.options,
|
|
340
340
|
evaluationParameters: normalizeEvaluationParametersForField(schemaField.type, schemaField.evaluationParameters),
|
|
341
341
|
};
|
|
@@ -4952,6 +4952,7 @@ const optionalPositiveInt = number().int().positive().optional();
|
|
|
4952
4952
|
const optionalString = string().optional();
|
|
4953
4953
|
const selectOptionsSchema = array(nonEmptyString).min(1);
|
|
4954
4954
|
const optionalNumber = number().optional();
|
|
4955
|
+
const expectedOutcomeModeSchema = _enum(['static', 'dynamic']);
|
|
4955
4956
|
const evaluationParametersSchema = object({
|
|
4956
4957
|
approach: _enum(EvaluationApproach),
|
|
4957
4958
|
threshold: optionalNumber,
|
|
@@ -5013,8 +5014,21 @@ const expectedOutcomeFieldSchema = discriminatedUnion('type', [
|
|
|
5013
5014
|
defaultFieldDefinitions.text.extend({
|
|
5014
5015
|
value: string(),
|
|
5015
5016
|
}),
|
|
5016
|
-
defaultFieldDefinitions.textarea
|
|
5017
|
+
defaultFieldDefinitions.textarea
|
|
5018
|
+
.extend({
|
|
5017
5019
|
value: string(),
|
|
5020
|
+
outcomeMode: expectedOutcomeModeSchema.default('static'),
|
|
5021
|
+
resolutionQuery: string().optional(),
|
|
5022
|
+
})
|
|
5023
|
+
.superRefine((field, ctx) => {
|
|
5024
|
+
if (field.outcomeMode === 'dynamic' &&
|
|
5025
|
+
(!field.resolutionQuery || field.resolutionQuery.trim().length === 0)) {
|
|
5026
|
+
ctx.addIssue({
|
|
5027
|
+
code: 'custom',
|
|
5028
|
+
path: ['resolutionQuery'],
|
|
5029
|
+
message: 'resolutionQuery is required when outcomeMode is dynamic.',
|
|
5030
|
+
});
|
|
5031
|
+
}
|
|
5018
5032
|
}),
|
|
5019
5033
|
defaultFieldDefinitions.chipsInput.extend({
|
|
5020
5034
|
value: array(string()).superRefine((values, ctx) => {
|
|
@@ -5108,6 +5122,50 @@ function importTestSuite(jsonContent) {
|
|
|
5108
5122
|
}
|
|
5109
5123
|
}
|
|
5110
5124
|
|
|
5125
|
+
const MISSING_RESOLVER_MESSAGE = 'resolveExpectedOutcome is required when a test case has dynamic expected outcomes.';
|
|
5126
|
+
function isDynamicTextareaField(field) {
|
|
5127
|
+
return field.type === 'textarea' && field.outcomeMode === 'dynamic';
|
|
5128
|
+
}
|
|
5129
|
+
function applyResolvedDynamicValues(testCase, resolvedValues) {
|
|
5130
|
+
if (resolvedValues.length === 0) {
|
|
5131
|
+
return testCase;
|
|
5132
|
+
}
|
|
5133
|
+
const expectedOutcome = [...(testCase.expectedOutcome || [])];
|
|
5134
|
+
for (const resolved of resolvedValues) {
|
|
5135
|
+
const field = expectedOutcome[resolved.index];
|
|
5136
|
+
if (!field || !isDynamicTextareaField(field)) {
|
|
5137
|
+
continue;
|
|
5138
|
+
}
|
|
5139
|
+
expectedOutcome[resolved.index] = {
|
|
5140
|
+
...field,
|
|
5141
|
+
value: resolved.value,
|
|
5142
|
+
};
|
|
5143
|
+
}
|
|
5144
|
+
return {
|
|
5145
|
+
...testCase,
|
|
5146
|
+
expectedOutcome,
|
|
5147
|
+
};
|
|
5148
|
+
}
|
|
5149
|
+
async function resolveDynamicExpectedOutcomes(testCase, resolver) {
|
|
5150
|
+
const dynamicFields = (testCase.expectedOutcome || []).flatMap((field, index) => {
|
|
5151
|
+
if (!isDynamicTextareaField(field)) {
|
|
5152
|
+
return [];
|
|
5153
|
+
}
|
|
5154
|
+
return [{ field, index }];
|
|
5155
|
+
});
|
|
5156
|
+
if (dynamicFields.length === 0) {
|
|
5157
|
+
return testCase;
|
|
5158
|
+
}
|
|
5159
|
+
if (!resolver) {
|
|
5160
|
+
throw new Error(MISSING_RESOLVER_MESSAGE);
|
|
5161
|
+
}
|
|
5162
|
+
const resolvedValues = await Promise.all(dynamicFields.map(async ({ field, index }) => ({
|
|
5163
|
+
index,
|
|
5164
|
+
value: await resolver(field.resolutionQuery || '', { testCase, fieldIndex: index }),
|
|
5165
|
+
})));
|
|
5166
|
+
return applyResolvedDynamicValues(testCase, resolvedValues);
|
|
5167
|
+
}
|
|
5168
|
+
|
|
5111
5169
|
function applyExpectedOutcomeChange(testCase, change) {
|
|
5112
5170
|
const { index } = change;
|
|
5113
5171
|
const expectedOutcome = [...(testCase.expectedOutcome || [])];
|
|
@@ -5120,6 +5178,9 @@ function applyExpectedOutcomeChange(testCase, change) {
|
|
|
5120
5178
|
if (target.type === 'chips-input') {
|
|
5121
5179
|
return testCase;
|
|
5122
5180
|
}
|
|
5181
|
+
if (target.type === 'textarea' && target.outcomeMode === 'dynamic') {
|
|
5182
|
+
return testCase;
|
|
5183
|
+
}
|
|
5123
5184
|
expectedOutcome[index] = {
|
|
5124
5185
|
...target,
|
|
5125
5186
|
value: change.value,
|
|
@@ -5148,6 +5209,38 @@ function applyExpectedOutcomeChange(testCase, change) {
|
|
|
5148
5209
|
}
|
|
5149
5210
|
case 'set-evaluation-approach':
|
|
5150
5211
|
return updateExpectedOutcomeFieldApproach(testCase, index, change.value);
|
|
5212
|
+
case 'set-outcome-mode': {
|
|
5213
|
+
if (target.type !== 'textarea') {
|
|
5214
|
+
return testCase;
|
|
5215
|
+
}
|
|
5216
|
+
const mode = change.value;
|
|
5217
|
+
if (mode === 'static') {
|
|
5218
|
+
const { resolutionQuery: _, ...rest } = target;
|
|
5219
|
+
expectedOutcome[index] = {
|
|
5220
|
+
...rest,
|
|
5221
|
+
outcomeMode: 'static',
|
|
5222
|
+
value: '',
|
|
5223
|
+
};
|
|
5224
|
+
}
|
|
5225
|
+
else {
|
|
5226
|
+
expectedOutcome[index] = {
|
|
5227
|
+
...target,
|
|
5228
|
+
outcomeMode: 'dynamic',
|
|
5229
|
+
value: '',
|
|
5230
|
+
};
|
|
5231
|
+
}
|
|
5232
|
+
return { ...testCase, expectedOutcome };
|
|
5233
|
+
}
|
|
5234
|
+
case 'set-resolution-query': {
|
|
5235
|
+
if (target.type !== 'textarea' || target.outcomeMode !== 'dynamic') {
|
|
5236
|
+
return testCase;
|
|
5237
|
+
}
|
|
5238
|
+
expectedOutcome[index] = {
|
|
5239
|
+
...target,
|
|
5240
|
+
resolutionQuery: change.value,
|
|
5241
|
+
};
|
|
5242
|
+
return { ...testCase, expectedOutcome };
|
|
5243
|
+
}
|
|
5151
5244
|
}
|
|
5152
5245
|
}
|
|
5153
5246
|
/**
|
|
@@ -30015,13 +30108,20 @@ class EvaluationService {
|
|
|
30015
30108
|
console.warn('⚠️ No output to evaluate for test case:', testCase.id);
|
|
30016
30109
|
return;
|
|
30017
30110
|
}
|
|
30018
|
-
const fields = (testCase.expectedOutcome || []).
|
|
30019
|
-
|
|
30020
|
-
|
|
30021
|
-
|
|
30022
|
-
|
|
30023
|
-
|
|
30024
|
-
|
|
30111
|
+
const fields = (testCase.expectedOutcome || []).flatMap((field, index) => {
|
|
30112
|
+
if (field.type === 'textarea' && field.outcomeMode === 'dynamic') {
|
|
30113
|
+
return [];
|
|
30114
|
+
}
|
|
30115
|
+
return [
|
|
30116
|
+
{
|
|
30117
|
+
index,
|
|
30118
|
+
label: field.label,
|
|
30119
|
+
type: field.type,
|
|
30120
|
+
expectedValue: getFieldExpectedValue(field),
|
|
30121
|
+
evaluationParameters: normalizeEvaluationParametersForField(field.type, field.evaluationParameters),
|
|
30122
|
+
},
|
|
30123
|
+
];
|
|
30124
|
+
});
|
|
30025
30125
|
const evaluationRequest = {
|
|
30026
30126
|
testCaseId: testCase.id,
|
|
30027
30127
|
question: testCase.question,
|
|
@@ -30116,7 +30216,7 @@ var FormFieldType;
|
|
|
30116
30216
|
FormFieldType["SELECT"] = "select";
|
|
30117
30217
|
})(FormFieldType || (FormFieldType = {}));
|
|
30118
30218
|
|
|
30119
|
-
const ExpectedOutcomeRenderer = ({ testCaseId, fields, onExpectedOutcomeChange, }) => {
|
|
30219
|
+
const ExpectedOutcomeRenderer = ({ testCaseId, fields, dynamicResolutionSupported = false, onExpectedOutcomeChange, }) => {
|
|
30120
30220
|
const emit = (detail) => onExpectedOutcomeChange({
|
|
30121
30221
|
detail,
|
|
30122
30222
|
});
|
|
@@ -30129,6 +30229,23 @@ const ExpectedOutcomeRenderer = ({ testCaseId, fields, onExpectedOutcomeChange,
|
|
|
30129
30229
|
optionList,
|
|
30130
30230
|
defaultValue: EvaluationApproach.EXACT,
|
|
30131
30231
|
});
|
|
30232
|
+
const buildOutcomeModeConfig = (index) => ({
|
|
30233
|
+
name: `expectedOutcomeMode-${index}`,
|
|
30234
|
+
fieldType: FormFieldType.SELECT,
|
|
30235
|
+
label: 'Outcome Mode',
|
|
30236
|
+
placeholder: 'Select outcome mode',
|
|
30237
|
+
required: true,
|
|
30238
|
+
optionList: ['static', 'dynamic'],
|
|
30239
|
+
defaultValue: 'static',
|
|
30240
|
+
});
|
|
30241
|
+
const buildResolutionQueryConfig = (index) => ({
|
|
30242
|
+
name: `expectedOutcomeResolutionQuery-${index}`,
|
|
30243
|
+
fieldType: FormFieldType.TEXT_AREA,
|
|
30244
|
+
label: 'Resolution Query',
|
|
30245
|
+
placeholder: 'Query used to resolve expected value',
|
|
30246
|
+
required: false,
|
|
30247
|
+
rows: 2,
|
|
30248
|
+
});
|
|
30132
30249
|
const renderEvaluationSelector = (field, index) => {
|
|
30133
30250
|
const optionList = getAllowedApproachesForFieldType(field.type);
|
|
30134
30251
|
return (h("app-select", { config: buildEvaluationConfig(index, optionList), value: field.evaluationParameters?.approach, onValueChange: (e) => emit({
|
|
@@ -30140,12 +30257,17 @@ const ExpectedOutcomeRenderer = ({ testCaseId, fields, onExpectedOutcomeChange,
|
|
|
30140
30257
|
};
|
|
30141
30258
|
return (h("div", { class: "expected-outcome-renderer" }, (fields || []).map((field, index) => {
|
|
30142
30259
|
if (field.type === 'textarea') {
|
|
30260
|
+
const isDynamic = dynamicResolutionSupported && field.outcomeMode === 'dynamic';
|
|
30143
30261
|
const config = {
|
|
30144
30262
|
name: `expectedOutcome-${index}`,
|
|
30145
30263
|
fieldType: FormFieldType.TEXT_AREA,
|
|
30146
30264
|
label: field.label,
|
|
30147
|
-
placeholder: field.placeholder,
|
|
30148
|
-
required:
|
|
30265
|
+
placeholder: isDynamic ? 'Resolved on run' : field.placeholder,
|
|
30266
|
+
required: !isDynamic,
|
|
30267
|
+
readOnly: isDynamic,
|
|
30268
|
+
helpText: isDynamic
|
|
30269
|
+
? 'Filled automatically when the test is run'
|
|
30270
|
+
: undefined,
|
|
30149
30271
|
rows: field.rows || 2,
|
|
30150
30272
|
};
|
|
30151
30273
|
return (h("div", { class: "expected-outcome-renderer__group" }, h("app-textarea", { config: config, value: field.value, onValueChange: (e) => emit({
|
|
@@ -30153,7 +30275,18 @@ const ExpectedOutcomeRenderer = ({ testCaseId, fields, onExpectedOutcomeChange,
|
|
|
30153
30275
|
index,
|
|
30154
30276
|
operation: 'set-value',
|
|
30155
30277
|
value: e.detail.value,
|
|
30156
|
-
}) }),
|
|
30278
|
+
}) }), dynamicResolutionSupported && (h("app-select", { config: buildOutcomeModeConfig(index), value: field.outcomeMode || 'static', onValueChange: (e) => emit({
|
|
30279
|
+
testCaseId,
|
|
30280
|
+
index,
|
|
30281
|
+
operation: 'set-outcome-mode',
|
|
30282
|
+
value: e.detail.value,
|
|
30283
|
+
}) })), dynamicResolutionSupported &&
|
|
30284
|
+
field.outcomeMode === 'dynamic' && (h("app-textarea", { config: buildResolutionQueryConfig(index), value: field.resolutionQuery || '', onValueChange: (e) => emit({
|
|
30285
|
+
testCaseId,
|
|
30286
|
+
index,
|
|
30287
|
+
operation: 'set-resolution-query',
|
|
30288
|
+
value: e.detail.value,
|
|
30289
|
+
}) })), !isDynamic && renderEvaluationSelector(field, index)));
|
|
30157
30290
|
}
|
|
30158
30291
|
if (field.type === 'chips-input') {
|
|
30159
30292
|
const config = {
|
|
@@ -30200,7 +30333,7 @@ const ExpectedOutcomeRenderer = ({ testCaseId, fields, onExpectedOutcomeChange,
|
|
|
30200
30333
|
})));
|
|
30201
30334
|
};
|
|
30202
30335
|
|
|
30203
|
-
const LLMTestCaseRow = ({ testCase, onRun, onDelete, handleTestCaseChange, onExpectedOutcomeChange, }) => {
|
|
30336
|
+
const LLMTestCaseRow = ({ testCase, dynamicResolutionSupported = false, onRun, onDelete, handleTestCaseChange, onExpectedOutcomeChange, }) => {
|
|
30204
30337
|
const questionConfig = {
|
|
30205
30338
|
name: 'question',
|
|
30206
30339
|
fieldType: FormFieldType.TEXT_AREA,
|
|
@@ -30216,11 +30349,11 @@ const LLMTestCaseRow = ({ testCase, onRun, onDelete, handleTestCaseChange, onExp
|
|
|
30216
30349
|
key: 'question',
|
|
30217
30350
|
value: e.detail.value,
|
|
30218
30351
|
},
|
|
30219
|
-
}) }), h(ExpectedOutcomeRenderer, { testCaseId: testCase.id, fields: testCase.expectedOutcome || [], onExpectedOutcomeChange: onExpectedOutcomeChange })), h(ResponseOutput, { output: testCase.output, isRunning: testCase.isRunning }), h(EvaluationSummary, { result: testCase.evaluationResult, isRunning: testCase.isRunning }), h(RowActions, { isRunning: testCase.isRunning, canRun: !!testCase.question.trim(), onRun: () => onRun(testCase), onDelete: () => onDelete(testCase.id) })));
|
|
30352
|
+
}) }), h(ExpectedOutcomeRenderer, { testCaseId: testCase.id, fields: testCase.expectedOutcome || [], dynamicResolutionSupported: dynamicResolutionSupported, onExpectedOutcomeChange: onExpectedOutcomeChange })), h(ResponseOutput, { output: testCase.output, isRunning: testCase.isRunning }), h(EvaluationSummary, { result: testCase.evaluationResult, isRunning: testCase.isRunning }), h(RowActions, { isRunning: testCase.isRunning, canRun: !!testCase.question.trim(), onRun: () => onRun(testCase), onDelete: () => onDelete(testCase.id) })));
|
|
30220
30353
|
};
|
|
30221
30354
|
|
|
30222
|
-
const LLMTestCases = ({ testCases, onRun, onDelete, onAddTestCase, handleTestCaseChange, onExpectedOutcomeChange, }) => {
|
|
30223
|
-
return (h("div", { class: "test-cases" }, h("div", { class: "test-cases__column-headers" }, h("div", { class: "test-cases__column-header" }, "Input"), h("div", { class: "test-cases__column-header" }, "Output"), h("div", { class: "test-cases__column-header" }, "Evaluation"), h("div", { class: "test-cases__column-header" }, "Actions")), testCases.map(testCase => (h(LLMTestCaseRow, { testCase: testCase, onRun: onRun, onDelete: onDelete, handleTestCaseChange: handleTestCaseChange, onExpectedOutcomeChange: onExpectedOutcomeChange }))), h("div", { class: "test-cases__add-section" }, h(Button, { variant: "outline", size: "md", onClick: onAddTestCase }, "+ Add Question"))));
|
|
30355
|
+
const LLMTestCases = ({ testCases, dynamicResolutionSupported = false, onRun, onDelete, onAddTestCase, handleTestCaseChange, onExpectedOutcomeChange, }) => {
|
|
30356
|
+
return (h("div", { class: "test-cases" }, h("div", { class: "test-cases__column-headers" }, h("div", { class: "test-cases__column-header" }, "Input"), h("div", { class: "test-cases__column-header" }, "Output"), h("div", { class: "test-cases__column-header" }, "Evaluation"), h("div", { class: "test-cases__column-header" }, "Actions")), testCases.map(testCase => (h(LLMTestCaseRow, { testCase: testCase, dynamicResolutionSupported: dynamicResolutionSupported, onRun: onRun, onDelete: onDelete, handleTestCaseChange: handleTestCaseChange, onExpectedOutcomeChange: onExpectedOutcomeChange }))), h("div", { class: "test-cases__add-section" }, h(Button, { variant: "outline", size: "md", onClick: onAddTestCase }, "+ Add Question"))));
|
|
30224
30357
|
};
|
|
30225
30358
|
|
|
30226
30359
|
const tokensCss = () => `:host{--spacing:0.25rem;--spacing-1:calc(var(--spacing) * 1);--spacing-2:calc(var(--spacing) * 2);--spacing-3:calc(var(--spacing) * 3);--spacing-4:calc(var(--spacing) * 4);--spacing-5:calc(var(--spacing) * 5);--spacing-6:calc(var(--spacing) * 6);--spacing-8:calc(var(--spacing) * 8);--spacing-10:calc(var(--spacing) * 10);--spacing-12:calc(var(--spacing) * 12);--spacing-16:calc(var(--spacing) * 16);--spacing-20:calc(var(--spacing) * 20);--spacing-24:calc(var(--spacing) * 24);--radius-none:0;--radius-sm:0.125rem;--radius-md:0.375rem;--radius-lg:0.5rem;--radius-xl:0.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--radius-full:9999px;--radius:var(--radius-lg);--font-size-xs:0.75rem;--font-size-sm:0.875rem;--font-size-base:1rem;--font-size-lg:1.125rem;--font-size-xl:1.25rem;--font-size-2xl:1.5rem;--font-size-3xl:1.875rem;--font-size-4xl:2.25rem;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--line-height-none:1;--line-height-tight:1.25;--line-height-snug:1.375;--line-height-normal:1.5;--line-height-relaxed:1.625;--line-height-loose:2;--letter-spacing-tight:-0.025em;--letter-spacing-normal:0;--letter-spacing-wide:0.05em;--shadow-sm:0 1px 2px 0 rgba(0, 0, 0, 0.05);--shadow-md:0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);--shadow-lg:0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);--shadow-xl:0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);--shadow-2xl:0 25px 50px -12px rgba(0, 0, 0, 0.25);--border-width:1px;--z-base:0;--z-dropdown:1000;--z-sticky:1100;--z-modal:1200;--z-popover:1300;--z-tooltip:1400;--opacity-disabled:0.5;--opacity-hover:0.8;--opacity-muted:0.6;--max-w-sm:24rem;--max-w-md:28rem;--max-w-lg:32rem;--max-w-xl:42rem;--max-w-2xl:48rem;--max-w-full:100%;--breakpoint-sm:640px;--breakpoint-md:768px;--breakpoint-lg:1024px;--breakpoint-xl:1280px;--breakpoint-2xl:1536px;--background:#ffffff;--foreground:#0a0a0a;--card:#ffffff;--card-foreground:#0a0a0a;--popover:#ffffff;--popover-foreground:#0a0a0a;--primary:#0a0a0a;--primary-foreground:#fafafa;--secondary:#f4f4f5;--secondary-foreground:#0a0a0a;--muted:#f4f4f5;--muted-foreground:#71717a;--accent:#f4f4f5;--accent-foreground:#0a0a0a;--destructive:#ef4444;--destructive-foreground:#fafafa;--border:#e4e4e7;--input:#e4e4e7;--ring:#3b82f6;--success:#10b981;--success-foreground:#fafafa;--warning:#f59e0b;--warning-foreground:#fafafa;--info:#3b82f6;--info-foreground:#fafafa}:host([data-theme='dark']){--background:#0a0a0a;--foreground:#fafafa;--card:#171717;--card-foreground:#fafafa;--popover:#171717;--popover-foreground:#fafafa;--primary:#fafafa;--primary-foreground:#0a0a0a;--secondary:#27272a;--secondary-foreground:#fafafa;--muted:#27272a;--muted-foreground:#a1a1aa;--accent:#27272a;--accent-foreground:#fafafa;--destructive:#dc2626;--destructive-foreground:#fafafa;--border:#27272a;--input:#27272a;--ring:#3b82f6;--success:#059669;--success-foreground:#fafafa;--warning:#d97706;--warning-foreground:#fafafa;--info:#2563eb;--info-foreground:#fafafa}`;
|
|
@@ -30256,6 +30389,7 @@ const LLMTestRunner = class {
|
|
|
30256
30389
|
delayMs = 500;
|
|
30257
30390
|
useSave = false;
|
|
30258
30391
|
usePromptEditor = false;
|
|
30392
|
+
resolveExpectedOutcome;
|
|
30259
30393
|
initialTestCases;
|
|
30260
30394
|
defaultExpectedOutcomeSchema;
|
|
30261
30395
|
testCases = [
|
|
@@ -30319,6 +30453,9 @@ const LLMTestRunner = class {
|
|
|
30319
30453
|
async resetSavingState() {
|
|
30320
30454
|
this.isSaving = false;
|
|
30321
30455
|
}
|
|
30456
|
+
async getTestCases() {
|
|
30457
|
+
return this.testCases;
|
|
30458
|
+
}
|
|
30322
30459
|
handleTestCaseChange = (event) => {
|
|
30323
30460
|
const { testCaseId, key, value } = event.detail;
|
|
30324
30461
|
this.testCases = this.testCases.map(tc => tc.id === testCaseId ? { ...tc, [key]: value } : tc);
|
|
@@ -30339,38 +30476,62 @@ const LLMTestRunner = class {
|
|
|
30339
30476
|
updateTestCase(id, updates) {
|
|
30340
30477
|
this.testCases = this.testCases.map(tc => tc.id === id ? { ...tc, ...updates } : tc);
|
|
30341
30478
|
}
|
|
30342
|
-
|
|
30343
|
-
const startTime = Date.now();
|
|
30344
|
-
this.updateTestCase(testCase.id, { isRunning: true });
|
|
30479
|
+
requestLlmText(testCase) {
|
|
30345
30480
|
return new Promise((resolve, reject) => {
|
|
30346
30481
|
this.llmRequest.emit({
|
|
30347
30482
|
prompt: testCase.question,
|
|
30348
|
-
resolve
|
|
30349
|
-
|
|
30350
|
-
|
|
30351
|
-
|
|
30352
|
-
|
|
30353
|
-
|
|
30354
|
-
|
|
30355
|
-
|
|
30356
|
-
|
|
30357
|
-
|
|
30358
|
-
|
|
30359
|
-
|
|
30360
|
-
|
|
30361
|
-
|
|
30362
|
-
|
|
30363
|
-
|
|
30364
|
-
|
|
30365
|
-
|
|
30366
|
-
|
|
30367
|
-
|
|
30368
|
-
|
|
30369
|
-
|
|
30370
|
-
|
|
30371
|
-
|
|
30483
|
+
resolve,
|
|
30484
|
+
reject,
|
|
30485
|
+
});
|
|
30486
|
+
});
|
|
30487
|
+
}
|
|
30488
|
+
throwError(reason) {
|
|
30489
|
+
throw reason instanceof Error ? reason : new Error(String(reason));
|
|
30490
|
+
}
|
|
30491
|
+
addErrorMessage(reason, fallback) {
|
|
30492
|
+
return reason instanceof Error ? reason.message : fallback;
|
|
30493
|
+
}
|
|
30494
|
+
async runSingleTest(testCase) {
|
|
30495
|
+
const startTime = Date.now();
|
|
30496
|
+
this.updateTestCase(testCase.id, { isRunning: true });
|
|
30497
|
+
const [llmSettled, resolutionSettled] = await Promise.allSettled([
|
|
30498
|
+
this.requestLlmText(testCase),
|
|
30499
|
+
resolveDynamicExpectedOutcomes(testCase, this.resolveExpectedOutcome),
|
|
30500
|
+
]);
|
|
30501
|
+
const responseTime = Date.now() - startTime;
|
|
30502
|
+
if (llmSettled.status === 'rejected') {
|
|
30503
|
+
this.updateTestCase(testCase.id, {
|
|
30504
|
+
isRunning: false,
|
|
30505
|
+
output: null,
|
|
30506
|
+
error: this.addErrorMessage(llmSettled.reason, 'Unknown error'),
|
|
30507
|
+
responseTime,
|
|
30372
30508
|
});
|
|
30509
|
+
this.throwError(llmSettled.reason);
|
|
30510
|
+
}
|
|
30511
|
+
const aiResponse = llmSettled.value;
|
|
30512
|
+
if (resolutionSettled.status === 'rejected') {
|
|
30513
|
+
this.updateTestCase(testCase.id, {
|
|
30514
|
+
isRunning: false,
|
|
30515
|
+
output: aiResponse,
|
|
30516
|
+
error: this.addErrorMessage(resolutionSettled.reason, 'Failed to resolve dynamic expected outcome.'),
|
|
30517
|
+
responseTime,
|
|
30518
|
+
});
|
|
30519
|
+
this.throwError(resolutionSettled.reason);
|
|
30520
|
+
}
|
|
30521
|
+
const resolvedTestCase = resolutionSettled.value;
|
|
30522
|
+
const forEvaluationTestCase = {
|
|
30523
|
+
...resolvedTestCase,
|
|
30524
|
+
output: aiResponse,
|
|
30525
|
+
responseTime,
|
|
30526
|
+
};
|
|
30527
|
+
this.updateTestCase(testCase.id, {
|
|
30528
|
+
isRunning: false,
|
|
30529
|
+
output: aiResponse,
|
|
30530
|
+
error: null,
|
|
30531
|
+
responseTime,
|
|
30532
|
+
expectedOutcome: forEvaluationTestCase.expectedOutcome,
|
|
30373
30533
|
});
|
|
30534
|
+
await this.evaluateResponse(forEvaluationTestCase);
|
|
30374
30535
|
}
|
|
30375
30536
|
deleteTestCase(id) {
|
|
30376
30537
|
this.testCases = this.testCases.filter(tc => tc.id !== id);
|
|
@@ -30481,7 +30642,7 @@ const LLMTestRunner = class {
|
|
|
30481
30642
|
}
|
|
30482
30643
|
}
|
|
30483
30644
|
render() {
|
|
30484
|
-
return (h("div", { key: '
|
|
30645
|
+
return (h("div", { key: '5536c02dcbf03e1d21de2df307f5255a17c000c7', class: "test-runner-container" }, h(LLMTestRunnerHeader, { key: 'b6b7db13d7b5576986f4de469c4eeff62b9be873', isExportingTestSuite: this.isExportingTestSuite, isExportingTestResults: this.isExportingTestResults, isRunningAll: this.isRunningAll, useSave: this.useSave, isSaving: this.isSaving, usePromptEditor: this.usePromptEditor, onImport: file => this.handleImport(file), onExportSuite: () => this.handleExportTestSuite(), onExportResults: () => this.handleExportTestResults(), onRunAll: () => this.runAllTests(), onSave: () => this.handleSave() }), h(ErrorMessage, { key: '48407658a40dd79864ddf24426df743df9206b30', message: this.error, onClear: () => (this.error = '') }), h("div", { key: '2b1db34dbb4defc98c255ca7bcb9318ca1c52cba', class: "test-runner-container__content" }, h(LLMTestCases, { key: '90b4d25f51d5de43790cabeb4fa6fc1c90c246cd', testCases: this.testCases, dynamicResolutionSupported: !!this.resolveExpectedOutcome, onRun: testCase => this.runSingleTest(testCase).catch(() => { }), onDelete: id => this.deleteTestCase(id), onAddTestCase: () => this.addNewTestCase(), handleTestCaseChange: this.handleTestCaseChange, onExpectedOutcomeChange: this.handleExpectedOutcomeChange }))));
|
|
30485
30646
|
}
|
|
30486
30647
|
};
|
|
30487
30648
|
LLMTestRunner.style = tokensCss() + (llmTestRunnerCss() + (llmTestRunnerHeaderCss() + (llmTestCasesCss() + (llmTestCaseRowCss() + (rowActionsCss() + (evaluationSummaryCss() + (responseOutputCss() + (errorMessageCss() + (buttonCss() + iconButtonCss())))))))));
|