diff --git a/OpenJibo/OpenJibo.sln.DotSettings b/OpenJibo/OpenJibo.sln.DotSettings
new file mode 100644
index 0000000..fd8e165
--- /dev/null
+++ b/OpenJibo/OpenJibo.sln.DotSettings
@@ -0,0 +1,2 @@
+
+ True
\ No newline at end of file
diff --git a/OpenJibo/OpenJibo.slnx b/OpenJibo/OpenJibo.slnx
index 3eac7e6..3990677 100644
--- a/OpenJibo/OpenJibo.slnx
+++ b/OpenJibo/OpenJibo.slnx
@@ -2,5 +2,8 @@
-
+
+
+
+
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/AnimateAction.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/AnimateAction.cs
new file mode 100644
index 0000000..d59dcd6
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/AnimateAction.cs
@@ -0,0 +1,8 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class AnimateAction : PlanAction
+{
+ public override PlanActionType Type => PlanActionType.Animate;
+ public string AnimationId { get; init; } = string.Empty;
+ public IDictionary Parameters { get; init; } = new Dictionary();
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/BrainDecision.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/BrainDecision.cs
new file mode 100644
index 0000000..7f6902f
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/BrainDecision.cs
@@ -0,0 +1,14 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class BrainDecision
+{
+ public BrainRoute Route { get; init; }
+ public string IntentName { get; init; } = string.Empty;
+ public float Confidence { get; init; }
+
+ public string? CapabilityName { get; init; }
+ public string? NativeSkillName { get; init; }
+
+ public IDictionary Slots { get; init; } = new Dictionary();
+ public IDictionary ContextUpdates { get; init; } = new Dictionary();
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/BrainRoute.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/BrainRoute.cs
new file mode 100644
index 0000000..4bfd988
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/BrainRoute.cs
@@ -0,0 +1,10 @@
+namespace Jibo.Runtime.Abstractions;
+
+public enum BrainRoute
+{
+ Rules = 0,
+ NativeSkill = 1,
+ LocalAi = 2,
+ CloudAi = 3,
+ Hybrid = 4
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/ConversationSession.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/ConversationSession.cs
new file mode 100644
index 0000000..dbf22d8
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/ConversationSession.cs
@@ -0,0 +1,15 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class ConversationSession
+{
+ public string SessionId { get; init; } = Guid.NewGuid().ToString("N");
+ public DateTimeOffset StartedUtc { get; init; } = DateTimeOffset.UtcNow;
+ public DateTimeOffset LastActivityUtc { get; set; } = DateTimeOffset.UtcNow;
+
+ public string? ActiveTopic { get; set; }
+ public string? LastIntent { get; set; }
+ public IDictionary Slots { get; } = new Dictionary();
+
+ public DateTimeOffset? FollowUpExpiresUtc { get; set; }
+ public bool FollowUpOpen => FollowUpExpiresUtc.HasValue && FollowUpExpiresUtc > DateTimeOffset.UtcNow;
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/FollowUpPolicy.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/FollowUpPolicy.cs
new file mode 100644
index 0000000..01cc806
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/FollowUpPolicy.cs
@@ -0,0 +1,11 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class FollowUpPolicy
+{
+ public static FollowUpPolicy None => new() { KeepMicOpen = false, Timeout = TimeSpan.Zero };
+
+ public bool KeepMicOpen { get; init; }
+ public TimeSpan Timeout { get; init; }
+ public string? ExpectedTopic { get; init; }
+ public IDictionary Hints { get; init; } = new Dictionary();
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/IBrainStrategy.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/IBrainStrategy.cs
new file mode 100644
index 0000000..98b249e
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/IBrainStrategy.cs
@@ -0,0 +1,11 @@
+namespace Jibo.Runtime.Abstractions;
+
+public interface IBrainStrategy
+{
+ string Name { get; }
+ bool CanHandle(TurnContext turn, ConversationSession session);
+ Task DecideAsync(
+ TurnContext turn,
+ ConversationSession session,
+ CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/IBrainStrategySelector.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/IBrainStrategySelector.cs
new file mode 100644
index 0000000..ecb9636
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/IBrainStrategySelector.cs
@@ -0,0 +1,9 @@
+namespace Jibo.Runtime.Abstractions;
+
+public interface IBrainStrategySelector
+{
+ Task SelectAsync(
+ TurnContext turn,
+ ConversationSession session,
+ CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/ICapability.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/ICapability.cs
new file mode 100644
index 0000000..2ffc5bf
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/ICapability.cs
@@ -0,0 +1,6 @@
+namespace Jibo.Runtime.Abstractions;
+
+public interface ICapability
+{
+ string Name { get; }
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/ICapabilityRegistry.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/ICapabilityRegistry.cs
new file mode 100644
index 0000000..9209cf0
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/ICapabilityRegistry.cs
@@ -0,0 +1,6 @@
+namespace Jibo.Runtime.Abstractions;
+
+public interface ICapabilityRegistry
+{
+ TCapability? Get(string name) where TCapability : class, ICapability;
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/IConversationBroker.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/IConversationBroker.cs
new file mode 100644
index 0000000..26b073e
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/IConversationBroker.cs
@@ -0,0 +1,6 @@
+namespace Jibo.Runtime.Abstractions;
+
+public interface IConversationBroker
+{
+ Task HandleTurnAsync(TurnContext turn, CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/IResponsePlanner.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/IResponsePlanner.cs
new file mode 100644
index 0000000..cc81369
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/IResponsePlanner.cs
@@ -0,0 +1,10 @@
+namespace Jibo.Runtime.Abstractions;
+
+public interface IResponsePlanner
+{
+ Task BuildPlanAsync(
+ TurnContext turn,
+ ConversationSession session,
+ BrainDecision decision,
+ CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/IRobotAdapter.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/IRobotAdapter.cs
new file mode 100644
index 0000000..c2133f0
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/IRobotAdapter.cs
@@ -0,0 +1,6 @@
+namespace Jibo.Runtime.Abstractions;
+
+public interface IRobotAdapter
+{
+ Task PublishPlanAsync(ResponsePlan plan, CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/IRobotEventMapper.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/IRobotEventMapper.cs
new file mode 100644
index 0000000..bfce0c6
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/IRobotEventMapper.cs
@@ -0,0 +1,6 @@
+namespace Jibo.Runtime.Abstractions;
+
+public interface IRobotEventMapper
+{
+ Task MapToTurnContextAsync(RobotEvent robotEvent, CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/IRobotEventSource.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/IRobotEventSource.cs
new file mode 100644
index 0000000..25dc807
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/IRobotEventSource.cs
@@ -0,0 +1,6 @@
+namespace Jibo.Runtime.Abstractions;
+
+public interface IRobotEventSource
+{
+ IAsyncEnumerable ReadEventsAsync(CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/ISttStrategy.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/ISttStrategy.cs
new file mode 100644
index 0000000..d65ac73
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/ISttStrategy.cs
@@ -0,0 +1,8 @@
+namespace Jibo.Runtime.Abstractions;
+
+public interface ISttStrategy
+{
+ string Name { get; }
+ bool CanHandle(TurnContext turn);
+ Task TranscribeAsync(TurnContext turn, CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/ISttStrategySelector.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/ISttStrategySelector.cs
new file mode 100644
index 0000000..72760d2
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/ISttStrategySelector.cs
@@ -0,0 +1,6 @@
+namespace Jibo.Runtime.Abstractions;
+
+public interface ISttStrategySelector
+{
+ Task SelectAsync(TurnContext turn, CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/IWeatherCapability.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/IWeatherCapability.cs
new file mode 100644
index 0000000..2c4b784
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/IWeatherCapability.cs
@@ -0,0 +1,6 @@
+namespace Jibo.Runtime.Abstractions;
+
+public interface IWeatherCapability : ICapability
+{
+ Task GetWeatherAsync(WeatherRequest request, CancellationToken cancellationToken = default);
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/InvokeNativeSkillAction.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/InvokeNativeSkillAction.cs
new file mode 100644
index 0000000..1fd5220
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/InvokeNativeSkillAction.cs
@@ -0,0 +1,8 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class InvokeNativeSkillAction : PlanAction
+{
+ public override PlanActionType Type => PlanActionType.InvokeNativeSkill;
+ public string SkillName { get; init; } = string.Empty;
+ public IDictionary Payload { get; init; } = new Dictionary();
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/Jibo.Runtime.Abstractions.csproj b/OpenJibo/src/Jibo.Runtime.Abstractions/Jibo.Runtime.Abstractions.csproj
new file mode 100644
index 0000000..b760144
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/Jibo.Runtime.Abstractions.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net10.0
+ enable
+ enable
+
+
+
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/ListenAction.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/ListenAction.cs
new file mode 100644
index 0000000..e433d2e
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/ListenAction.cs
@@ -0,0 +1,8 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class ListenAction : PlanAction
+{
+ public override PlanActionType Type => PlanActionType.Listen;
+ public TimeSpan Timeout { get; init; }
+ public string? Mode { get; init; } // follow-up, open-mic, command
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/PlanAction.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/PlanAction.cs
new file mode 100644
index 0000000..912e301
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/PlanAction.cs
@@ -0,0 +1,7 @@
+namespace Jibo.Runtime.Abstractions;
+
+public abstract class PlanAction
+{
+ public abstract PlanActionType Type { get; }
+ public int Sequence { get; init; }
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/PlanActionType.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/PlanActionType.cs
new file mode 100644
index 0000000..ae96bde
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/PlanActionType.cs
@@ -0,0 +1,12 @@
+namespace Jibo.Runtime.Abstractions;
+
+public enum PlanActionType
+{
+ Speak = 0,
+ Listen = 1,
+ ShowVisual = 2,
+ Animate = 3,
+ InvokeNativeSkill = 4,
+ SetContext = 5,
+ EmitEvent = 6
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/ResponsePlan.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/ResponsePlan.cs
new file mode 100644
index 0000000..6f17faa
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/ResponsePlan.cs
@@ -0,0 +1,18 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class ResponsePlan
+{
+ public string PlanId { get; init; } = Guid.NewGuid().ToString("N");
+ public string SessionId { get; init; } = string.Empty;
+ public ResponseStatus Status { get; init; } = ResponseStatus.Succeeded;
+
+ public string? IntentName { get; init; }
+ public string? Topic { get; init; }
+ public IList Actions { get; init; } = new List();
+
+ public FollowUpPolicy FollowUp { get; init; } = FollowUpPolicy.None;
+ public IDictionary ContextUpdates { get; init; } = new Dictionary();
+
+ public string? DebugRoute { get; init; }
+ public IDictionary Diagnostics { get; init; } = new Dictionary();
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/ResponseStatus.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/ResponseStatus.cs
new file mode 100644
index 0000000..dff33ce
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/ResponseStatus.cs
@@ -0,0 +1,9 @@
+namespace Jibo.Runtime.Abstractions;
+
+public enum ResponseStatus
+{
+ Succeeded = 0,
+ Failed = 1,
+ Escalated = 2,
+ NoMatch = 3
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/RobotEvent.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/RobotEvent.cs
new file mode 100644
index 0000000..7e66cee
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/RobotEvent.cs
@@ -0,0 +1,14 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class RobotEvent
+{
+ public string EventId { get; init; } = Guid.NewGuid().ToString("N");
+ public DateTimeOffset TimestampUtc { get; init; } = DateTimeOffset.UtcNow;
+
+ public string EventType { get; init; } = string.Empty;
+ public string? SessionId { get; init; }
+ public string? Transcript { get; init; }
+ public string? WakePhrase { get; init; }
+
+ public IDictionary Payload { get; init; } = new Dictionary();
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/SetContextAction.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/SetContextAction.cs
new file mode 100644
index 0000000..ac70472
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/SetContextAction.cs
@@ -0,0 +1,7 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class SetContextAction : PlanAction
+{
+ public override PlanActionType Type => PlanActionType.SetContext;
+ public IDictionary Values { get; init; } = new Dictionary();
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/ShowVisualAction.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/ShowVisualAction.cs
new file mode 100644
index 0000000..07b597f
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/ShowVisualAction.cs
@@ -0,0 +1,8 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class ShowVisualAction : PlanAction
+{
+ public override PlanActionType Type => PlanActionType.ShowVisual;
+ public string VisualId { get; init; } = string.Empty;
+ public IDictionary Parameters { get; init; } = new Dictionary();
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/SpeakAction.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/SpeakAction.cs
new file mode 100644
index 0000000..389e9e3
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/SpeakAction.cs
@@ -0,0 +1,10 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class SpeakAction : PlanAction
+{
+ public override PlanActionType Type => PlanActionType.Speak;
+ public string Text { get; init; } = string.Empty;
+ public string? Voice { get; init; }
+ public string? Style { get; init; }
+ public bool CanBeInterrupted { get; init; } = true;
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/SttResult.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/SttResult.cs
new file mode 100644
index 0000000..c4f55f5
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/SttResult.cs
@@ -0,0 +1,10 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class SttResult
+{
+ public string Text { get; init; } = string.Empty;
+ public string? Provider { get; init; }
+ public float? Confidence { get; init; }
+ public string? Locale { get; init; }
+ public IDictionary Metadata { get; init; } = new Dictionary();
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/TurnContext.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/TurnContext.cs
new file mode 100644
index 0000000..169649f
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/TurnContext.cs
@@ -0,0 +1,21 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class TurnContext
+{
+ public string TurnId { get; init; } = Guid.NewGuid().ToString("N");
+ public string SessionId { get; init; } = string.Empty;
+ public DateTimeOffset TimestampUtc { get; init; } = DateTimeOffset.UtcNow;
+
+ public TurnInputMode InputMode { get; init; }
+ public TurnSourceKind SourceKind { get; init; }
+
+ public string? WakePhrase { get; init; }
+ public string? RawTranscript { get; init; }
+ public string? NormalizedTranscript { get; init; }
+
+ public string? Locale { get; init; } = "en-US";
+ public string? TimeZone { get; init; }
+
+ public bool IsFollowUpEligible { get; init; }
+ public IDictionary Attributes { get; init; } = new Dictionary();
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/TurnInputMode.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/TurnInputMode.cs
new file mode 100644
index 0000000..e77ddac
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/TurnInputMode.cs
@@ -0,0 +1,9 @@
+namespace Jibo.Runtime.Abstractions;
+
+public enum TurnInputMode
+{
+ WakeWord = 0,
+ FollowUp = 1,
+ DirectText = 2,
+ System = 3
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/TurnSourceKind.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/TurnSourceKind.cs
new file mode 100644
index 0000000..bd23cf0
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/TurnSourceKind.cs
@@ -0,0 +1,9 @@
+namespace Jibo.Runtime.Abstractions;
+
+public enum TurnSourceKind
+{
+ NativeJibo = 0,
+ Simulator = 1,
+ TestHarness = 2,
+ Api = 3
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/WeatherRequest.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/WeatherRequest.cs
new file mode 100644
index 0000000..e0837f8
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/WeatherRequest.cs
@@ -0,0 +1,9 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class WeatherRequest
+{
+ public string? LocationName { get; init; }
+ public string? TimeZone { get; init; }
+ public bool IncludeHourly { get; init; }
+ public bool IncludeDaily { get; init; }
+}
\ No newline at end of file
diff --git a/OpenJibo/src/Jibo.Runtime.Abstractions/WeatherResult.cs b/OpenJibo/src/Jibo.Runtime.Abstractions/WeatherResult.cs
new file mode 100644
index 0000000..77af25f
--- /dev/null
+++ b/OpenJibo/src/Jibo.Runtime.Abstractions/WeatherResult.cs
@@ -0,0 +1,12 @@
+namespace Jibo.Runtime.Abstractions;
+
+public sealed class WeatherResult
+{
+ public string Summary { get; init; } = string.Empty;
+ public int? CurrentTemperatureF { get; init; }
+ public int? HighTodayF { get; init; }
+ public int? LowTonightF { get; init; }
+ public string? Conditions { get; init; }
+ public string? LocationLabel { get; init; }
+ public IDictionary Raw { get; init; } = new Dictionary();
+}
\ No newline at end of file
diff --git a/OpenJibo/Playground/Playground.csproj b/OpenJibo/src/Playground/Playground.csproj
similarity index 100%
rename from OpenJibo/Playground/Playground.csproj
rename to OpenJibo/src/Playground/Playground.csproj
diff --git a/OpenJibo/Playground/Program.cs b/OpenJibo/src/Playground/Program.cs
similarity index 100%
rename from OpenJibo/Playground/Program.cs
rename to OpenJibo/src/Playground/Program.cs