Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .mvn/maven.config
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
-ntp
# timefold-solver-service-parent configures maven plugins required for Timefold models, but failing the build
# of that module itself. This way, we disable the plugin execution, while it remains active by default for models.
-Dai.timefold.sdk.model.processing.disabled
-Dai.timefold.model.processing.disabled
16 changes: 8 additions & 8 deletions service/facade/service-parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@
<skipUTs>${skipTests}</skipUTs>

<!--suppress UnresolvedMavenProperty -->
<ai.timefold.platform.model.test.api-key>${env.TF_PLATFORM_TEST_API_KEY}</ai.timefold.platform.model.test.api-key>
<ai.timefold.model.test.api-key>${env.TF_PLATFORM_TEST_API_KEY}</ai.timefold.model.test.api-key>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<!-- the application version defines the API version of the model -->
<timefold.application.version>v1</timefold.application.version>
<ai.timefold.model.api-version>v1</ai.timefold.model.api-version>
<!-- default configuration, can be overridden by a model if needed -->
<ai.timefold.model.descriptor.repository>${project.artifactId}</ai.timefold.model.descriptor.repository>
<ai.timefold.model.native.image.path>${project.build.directory}/${project.build.finalName}-runner</ai.timefold.model.native.image.path>
<ai.timefold.model.descriptor.groupId>${project.groupId}</ai.timefold.model.descriptor.groupId>
<ai.timefold.model.descriptor.artifactId>${project.artifactId}-descriptor</ai.timefold.model.descriptor.artifactId>
<ai.timefold.model.descriptor.classifier>${timefold.application.version}</ai.timefold.model.descriptor.classifier>
<ai.timefold.model.descriptor.classifier>${ai.timefold.model.api-version}</ai.timefold.model.descriptor.classifier>
<ai.timefold.model.descriptor.version>${project.version}</ai.timefold.model.descriptor.version>
<ai.timefold.model.descriptor.file>${project.build.directory}/model-descriptor.zip</ai.timefold.model.descriptor.file>
<ai.timefold.model.descriptor.repository.id>github</ai.timefold.model.descriptor.repository.id>
Expand Down Expand Up @@ -428,7 +428,7 @@
<missing>${project.basedir}/src/build/openapi.json</missing>
</file>
<property>
<name>ai.timefold.sdk.model.processing.disabled</name>
<name>ai.timefold.model.processing.disabled</name>
<value>!true</value>
</property>
</activation>
Expand Down Expand Up @@ -578,7 +578,7 @@
<id>timefold-model</id>
<activation>
<property>
<name>ai.timefold.sdk.model.processing.disabled</name>
<name>ai.timefold.model.processing.disabled</name>
<value>!true</value>
</property>
<!-- Switch to the activation below after our CI moves to Maven 3.9
Expand All @@ -596,7 +596,7 @@
<extensions>true</extensions>
<configuration>
<properties>
<timefold.application.version>${timefold.application.version}</timefold.application.version>
<ai.timefold.model.api-version>${ai.timefold.model.api-version}</ai.timefold.model.api-version>
</properties>
</configuration>
<executions>
Expand Down Expand Up @@ -951,8 +951,8 @@
<!--suppress UnresolvedMavenProperty -->
<maven.home>${maven.home}</maven.home>

<ai.timefold.platform.model.test.api-key>${ai.timefold.platform.model.test.api-key}
</ai.timefold.platform.model.test.api-key>
<ai.timefold.model.test.api-key>${ai.timefold.model.test.api-key}
</ai.timefold.model.test.api-key>
<quarkus.http.test-host>sandbox.timefold.dev</quarkus.http.test-host>
<quarkus.http.test-ssl-port>443</quarkus.http.test-ssl-port>
<quarkus.http.test-ssl-enabled>true</quarkus.http.test-ssl-enabled>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ public MapServiceOptionsSupplier(
@ConfigProperty(name = "ai.timefold.platform.map-service.location") Optional<String> location,
@ConfigProperty(
name = "ai.timefold.platform.map-service.max-distance-from-road") Optional<Double> maxDistanceFromRoad,
@ConfigProperty(name = "ai.timefold.platform.model") Optional<String> model,
@ConfigProperty(name = "ai.timefold.platform.model-version") Optional<String> modelVersion,
@ConfigProperty(name = "ai.timefold.platform.model-resource") Optional<String> modelResource,
@ConfigProperty(name = "ai.timefold.model.id") Optional<String> model,
@ConfigProperty(name = "ai.timefold.model.api-version") Optional<String> modelVersion,
@ConfigProperty(name = "ai.timefold.model.rest-resource") Optional<String> modelResource,
@ConfigProperty(name = "ai.timefold.platform.tenant-id") Optional<String> tenantId,
@ConfigProperty(name = "ai.timefold.platform.map-service.transport-type") Optional<String> transportType) {
this.provider = provider;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,35 +151,35 @@ class TimefoldModelDescriptorProcessor {
private static final String RESPONSE_CODE_TOO_MANY_REQUESTS = "429";

private static final List<String> CONFIG_PROPERTIES = List.of(
"ai.timefold.platform.termination.spent-limit",
"ai.timefold.platform.termination.maximum-spent-limit",
"ai.timefold.platform.termination.unimproved-spent-limit",
"ai.timefold.platform.termination.maximum-unimproved-spent-limit",
"ai.timefold.model.termination.spent-limit",
"ai.timefold.model.termination.maximum-spent-limit",
"ai.timefold.model.termination.unimproved-spent-limit",
"ai.timefold.model.termination.maximum-unimproved-spent-limit",
Comment on lines +154 to +157

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is also configured in the platform. Do we want to keep them with a model prefix?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the problem. Many properties are injected by the platform, yet they are configured in application.properties as well, typically for local runs and testing. Termination is a typical example of that, see e.g. https://github.com/TimefoldAI/timefold-employee-scheduling/blob/main/src/main/resources/application.properties#L50-L74.

Not all of them can be solved by good defaults. Some we even describe in the documentation.

Most of them are actually settings of the model, just take different values in the platform and locally.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with that 👍

"ai.timefold.platform.map-service.max-distance-from-road");

private static final String MODEL_MATURITY_LEVEL_PROPERTY = "timefold.model.maturity-level";
private static final String MODEL_MATURITY_LEVEL_PROPERTY = "ai.timefold.model.maturity-level";

private static final String MODEL_FEATURES_PROPERTY = "timefold.model.features";
private static final String MODEL_FEATURES_PROPERTY = "ai.timefold.model.features";

private static final String MODEL_MAX_THREAD_COUNT_PROPERTY = "ai.timefold.model.max-thread-count";

private static final String APPLICATION_NAME_PROPERTY = "timefold.application.name";
private static final String APPLICATION_DESCRIPTION_PROPERTY = "timefold.application.description";
static final String APPLICATION_VERSION_PROPERTY = "timefold.application.version";
private static final String APPLICATION_NAME_PROPERTY = "ai.timefold.model.name";
private static final String APPLICATION_DESCRIPTION_PROPERTY = "ai.timefold.model.description";
static final String APPLICATION_VERSION_PROPERTY = "ai.timefold.model.api-version";

private static final String MODEL_TRIAL_DURATION_PROPERTY = "timefold.model.trial.duration";
private static final String MODEL_TRIAL_MAX_EXTENSIONS_PROPERTY = "timefold.model.trial.max-extensions";
private static final String MODEL_TRIAL_EXTENSION_DURATION_PROPERTY = "timefold.model.trial.extension-duration";
private static final String MODEL_TRIAL_DURATION_PROPERTY = "ai.timefold.model.trial.duration";
private static final String MODEL_TRIAL_MAX_EXTENSIONS_PROPERTY = "ai.timefold.model.trial.max-extensions";
private static final String MODEL_TRIAL_EXTENSION_DURATION_PROPERTY = "ai.timefold.model.trial.extension-duration";

private static final String MEMORY_REQUEST_PROPERTY = "timefold.model.resources.memory.request";
private static final String MEMORY_LIMIT_PROPERTY = "timefold.model.resources.memory.limit";
private static final String CPU_REQUEST_PROPERTY = "timefold.model.resources.cpu.request";
private static final String CPU_LIMIT_PROPERTY = "timefold.model.resources.cpu.limit";
private static final String MEMORY_REQUEST_PROPERTY = "ai.timefold.model.resources.memory.request";
private static final String MEMORY_LIMIT_PROPERTY = "ai.timefold.model.resources.memory.limit";
private static final String CPU_REQUEST_PROPERTY = "ai.timefold.model.resources.cpu.request";
private static final String CPU_LIMIT_PROPERTY = "ai.timefold.model.resources.cpu.limit";

private static final String DOCUMENTATION_SUPPORT_PROPERTY = "timefold.model.documentation.support";
private static final String DOCUMENTATION_SOURCE_PROPERTY = "timefold.model.documentation.source";
private static final String DOCUMENTATION_SUPPORT_PROPERTY = "ai.timefold.model.documentation.support";
private static final String DOCUMENTATION_SOURCE_PROPERTY = "ai.timefold.model.documentation.source";

private static final String UI_SUPPORT_PROPERTY = "timefold.model.ui-support";
private static final String UI_SUPPORT_PROPERTY = "ai.timefold.model.ui-support";
private static final Path APP_JS_SOURCE_PATH = Path.of("src", "main", "resources", "META-INF", "resources");

// To avoid depending on the whole OpenAPI, we use the fully qualified class name.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import io.quarkus.runtime.annotations.ConfigRoot;
import io.smallrye.config.ConfigMapping;

@ConfigMapping(prefix = "timefold.model.visualization")
@ConfigMapping(prefix = "ai.timefold.model.visualization")
@ConfigRoot(phase = ConfigPhase.BUILD_TIME)
public interface VisualizationPagesConfig {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ void validVersionDoesNotThrow() {
void nullVersionThrows() {
assertThatThrownBy(() -> validateApplicationVersion(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("timefold.application.version");
.hasMessageContaining("ai.timefold.model.api-version");
}

@Test
void emptyVersionThrows() {
assertThatThrownBy(() -> validateApplicationVersion(""))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("timefold.application.version");
.hasMessageContaining("ai.timefold.model.api-version");
}

@Test
void blankVersionThrows() {
assertThatThrownBy(() -> validateApplicationVersion(" "))
.isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("timefold.application.version");
.hasMessageContaining("ai.timefold.model.api-version");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ void noPagesConfigured() {
@Test
void multiplePagesInOrder() {
VisualizationPagesConfig config = buildConfig(Map.of(
"timefold.model.visualization.pages[0].key", "data",
"timefold.model.visualization.pages[0].icon", "TbDatabase",
"timefold.model.visualization.pages[0].label", "Data",
"timefold.model.visualization.pages[1].key", "visualization",
"timefold.model.visualization.pages[1].icon", "TbEye",
"timefold.model.visualization.pages[1].label", "Visualization"));
"ai.timefold.model.visualization.pages[0].key", "data",
"ai.timefold.model.visualization.pages[0].icon", "TbDatabase",
"ai.timefold.model.visualization.pages[0].label", "Data",
"ai.timefold.model.visualization.pages[1].key", "visualization",
"ai.timefold.model.visualization.pages[1].icon", "TbEye",
"ai.timefold.model.visualization.pages[1].label", "Visualization"));

assertThat(TimefoldModelDescriptorProcessor.toVisualizationPageDescriptors(config))
.containsExactly(
Expand All @@ -50,10 +50,10 @@ void multiplePagesInOrder() {
@Test
void missingFieldFailsToBind() {
Map<String, String> properties = Map.of(
"timefold.model.visualization.pages[0].key", "visualization",
"timefold.model.visualization.pages[0].label", "Visualization");
"ai.timefold.model.visualization.pages[0].key", "visualization",
"ai.timefold.model.visualization.pages[0].label", "Visualization");

assertThatThrownBy(() -> buildConfig(properties))
.hasMessageContaining("timefold.model.visualization.pages[0].icon");
.hasMessageContaining("ai.timefold.model.visualization.pages[0].icon");
}
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
########################
# Timefold application info
########################
timefold.application.name=Timefold SDK - Integration Tests
timefold.application.version=v1
ai.timefold.model.name=Timefold SDK - Integration Tests
ai.timefold.model.api-version=v1

########################
# OpenAPI ans swagger ui configuration
########################
quarkus.swagger-ui.always-include=true
quarkus.swagger-ui.title=${timefold.application.name}
quarkus.swagger-ui.title=${ai.timefold.model.name}
quarkus.smallrye-openapi.store-schema-directory=target/openapi-schema
mp.openapi.extensions.smallrye.info.title=${timefold.application.name}
mp.openapi.extensions.smallrye.info.version=${timefold.application.version}
mp.openapi.extensions.smallrye.info.title=${ai.timefold.model.name}
mp.openapi.extensions.smallrye.info.version=${ai.timefold.model.api-version}

ai.timefold.storage.path=target
ai.timefold.storage.ttl=P1D
Expand All @@ -20,7 +20,7 @@ ai.timefold.model.default-config.resources.memory.mi=256
ai.timefold.model.default-config.resources.cpu.cores=1
ai.timefold.model.default-config.termination.spent-limit=PT30M
ai.timefold.model.default-config.termination.unimproved-spent-limit=PT5M
ai.timefold.platform.termination.spent-limit=PT30S
ai.timefold.model.termination.spent-limit=PT30S

# Useful for verifying bytecode generated using Gizmo
#quarkus.package.jar.decompiler.enabled=true
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class ValidatingReaderInterceptorContext implements ReaderInterceptor {

@Inject
public ValidatingReaderInterceptorContext(@All List<Validator<ObjectNode>> validators, ObjectMapper mapper,
@ConfigProperty(name = "ai.timefold.platform.models.validation.enable", defaultValue = "true") boolean enabled) {
@ConfigProperty(name = "ai.timefold.model.schema.validation.enable", defaultValue = "true") boolean enabled) {
this.validators = validators;
this.mapper = mapper;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,40 @@ config_ordinal=230
#######################################
# To be overridden by the actual model
#######################################
timefold.application.id=custom-timefold-model
timefold.application.name=Custom Timefold model
timefold.application.description=
timefold.application.build-timestamp=
timefold.application.contact.email=
timefold.application.contact.name=
timefold.application.contact.url=
ai.timefold.model.id=custom-timefold-model
ai.timefold.model.name=Custom Timefold model
ai.timefold.model.description=
ai.timefold.model.build-timestamp=
ai.timefold.model.contact.email=
ai.timefold.model.contact.name=
ai.timefold.model.contact.url=

#############################
# Default generic storage configuration
#############################

ai.timefold.storage.bucket=${timefold.application.id}
ai.timefold.storage.bucket=${ai.timefold.model.id}

###########################################
# Default solver termination configuration
###########################################

ai.timefold.platform.termination.spent-limit=PT10M
ai.timefold.model.termination.spent-limit=PT10M
# disabling the unimproved-spent-limit enables Diminished Returns termination
ai.timefold.platform.termination.unimproved-spent-limit=
ai.timefold.model.termination.unimproved-spent-limit=

%dev.ai.timefold.platform.termination.spent-limit=PT30S
%dev.ai.timefold.platform.termination.unimproved-spent-limit=
%dev.ai.timefold.model.termination.spent-limit=PT30S
%dev.ai.timefold.model.termination.unimproved-spent-limit=

#############################
# Default test configuration
#############################
%test.quarkus.timefold.solver.environment-mode=FULL_ASSERT

%test.ai.timefold.platform.termination.spent-limit=PT10S
%test.ai.timefold.platform.termination.unimproved-spent-limit=PT1S
%test.ai.timefold.model.termination.spent-limit=PT10S
%test.ai.timefold.model.termination.unimproved-spent-limit=PT1S
# Effectively disable termination in favor of the best-score-limit
%test.ai.timefold.platform.termination.best-score-limit=0hard/0medium/*soft
%test.ai.timefold.model.termination.best-score-limit=0hard/0medium/*soft

# Some of the tests may use SolverManager directly, declare solver's out-of-the-box variables
%test.quarkus.timefold.solver.termination.spent-limit=PT10S
Expand Down Expand Up @@ -83,7 +83,7 @@ quarkus.log.console.darken=1
########################
# REST API configuration
########################
quarkus.rest.path=${timefold.application.version}
quarkus.rest.path=${ai.timefold.model.api-version}

Comment on lines 83 to 87
# Workaround for https://github.com/quarkusio/quarkus/issues/55362
quarkus.rest.jackson.optimization.enable-reflection-free-serializers=false
Expand All @@ -92,25 +92,25 @@ quarkus.rest.jackson.optimization.enable-reflection-free-serializers=false
# OpenAPI and swagger ui configuration
########################
quarkus.swagger-ui.always-include=true
quarkus.swagger-ui.title=${timefold.application.name}
quarkus.swagger-ui.title=${ai.timefold.model.name}
quarkus.smallrye-openapi.store-schema-directory=target/openapi-schema
mp.openapi.extensions.smallrye.info.title=${timefold.application.name}
mp.openapi.extensions.smallrye.info.version=${timefold.application.version}
mp.openapi.extensions.smallrye.info.description=${timefold.application.description}
mp.openapi.extensions.smallrye.info.contact.email=${timefold.application.contact.email}
mp.openapi.extensions.smallrye.info.contact.name=${timefold.application.contact.name}
mp.openapi.extensions.smallrye.info.contact.url=${timefold.application.contact.url}
mp.openapi.extensions.smallrye.info.title=${ai.timefold.model.name}
mp.openapi.extensions.smallrye.info.version=${ai.timefold.model.api-version}
mp.openapi.extensions.smallrye.info.description=${ai.timefold.model.description}
mp.openapi.extensions.smallrye.info.contact.email=${ai.timefold.model.contact.email}
mp.openapi.extensions.smallrye.info.contact.name=${ai.timefold.model.contact.name}
mp.openapi.extensions.smallrye.info.contact.url=${ai.timefold.model.contact.url}
mp.openapi.extensions.smallrye.remove-unused-schemas.enable=true

########################
# Container configuration
########################
image.native-suffix=-native
# the end model should also set %container.quarkus.container-image.group
%container.quarkus.container-image.name=model-${timefold.application.id}-${timefold.application.version}
%container.quarkus.container-image.name=model-${ai.timefold.model.id}-${ai.timefold.model.api-version}

# the end model should also set %container-native.quarkus.container-image.group
%container-native.quarkus.container-image.name=model-${timefold.application.id}-${timefold.application.version}${image.native-suffix}
%container-native.quarkus.container-image.name=model-${ai.timefold.model.id}-${ai.timefold.model.api-version}${image.native-suffix}

########################################################################
# Default configuration profile settings relevant for the platform only
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
########################
# Timefold application info
########################
timefold.application.name=Integration Tests - Simplified Employee Shift Scheduling model
timefold.application.id=integration-tests-simplified-employee-shift-scheduling
%test.ai.timefold.platform.termination.best-score-limit=0hard/0medium/*soft
ai.timefold.model.name=Integration Tests - Simplified Employee Shift Scheduling model
ai.timefold.model.id=integration-tests-simplified-employee-shift-scheduling
%test.ai.timefold.model.termination.best-score-limit=0hard/0medium/*soft
Loading
Loading