Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extracting plan json from ActionPlanner result #1802

Merged
merged 14 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Parsing plan json from ActionPlanner result
  • Loading branch information
teresaqhoang committed Jun 30, 2023
commit 64168afccd6eca2d29b5647485c870accb792299
38 changes: 28 additions & 10 deletions dotnet/src/Extensions/Planning.ActionPlanner/ActionPlanner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
Expand Down Expand Up @@ -83,22 +84,39 @@ public async Task<Plan> CreatePlanAsync(string goal)
SKContext result = await this._plannerFunction.InvokeAsync(this._context).ConfigureAwait(false);

ActionPlanResponse? planData;
try

/* Filter out good JSON from the result in case additional text is present:
* Follows the balancing group regex defined here: https://learn.microsoft.com/en-us/dotnet/standard/base-types/grouping-constructs-in-regular-expressions#balancing-group-definitions
*/
Regex planRegex = new(@"^[^{}]*(((?'Open'{)[^{}]*)+((?'Close-Open'})[^{}]*)+)*(?(Open)(?!))", RegexOptions.Singleline);
Match match = planRegex.Match(result.ToString());

if (match.Success && match.Groups["Close"].Length > 0)
{
planData = JsonSerializer.Deserialize<ActionPlanResponse?>(result.ToString(), new JsonSerializerOptions
string planJson = $"{{{match.Groups["Close"].Value}}}";
try
{
planData = JsonSerializer.Deserialize<ActionPlanResponse?>(planJson, new JsonSerializerOptions
{
AllowTrailingCommas = true,
DictionaryKeyPolicy = null,
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
PropertyNameCaseInsensitive = true,
});
}
catch (Exception e)
{
AllowTrailingCommas = true,
DictionaryKeyPolicy = null,
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
PropertyNameCaseInsensitive = true,
});
throw new PlanningException(PlanningException.ErrorCodes.InvalidPlan,
"Plan parsing error, invalid JSON", e);
}
}
catch (Exception e)
else
{
throw new PlanningException(PlanningException.ErrorCodes.InvalidPlan,
"Plan parsing error, invalid JSON", e);
throw new PlanningException(PlanningException.ErrorCodes.InvalidPlan, $"Failed to parse plan json string: '{result.ToString()}'");
}



if (planData == null)
{
throw new PlanningException(PlanningException.ErrorCodes.InvalidPlan, "The plan deserialized to a null object");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,13 +125,13 @@ public async Task<string> AcquireExternalInformationAsync(string userIntent, SKC

if (plan.Steps.Count > 0)
{
// Parameters stored in plan's top level state
this.MergeContextIntoPlan(context.Variables, plan.State);
// Parameters stored in plan's top level
this.MergeContextIntoPlan(context.Variables, plan.Parameters);

// TODO: Improve Kernel to give developers option to skip this override
// (i.e., keep functions regardless of whether they're available in the planner's context or not)
Plan sanitizedPlan = this.SanitizePlan(plan, context);
sanitizedPlan.State.Update(plan.State);
sanitizedPlan.Parameters.Update(plan.Parameters);

this.ProposedPlan = new ProposedPlan(sanitizedPlan, this._planner.PlannerOptions!.Type, PlanState.NoOp);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,9 @@ export const PlanViewer: React.FC<PlanViewerProps> = ({ message, messageIndex, g

var planState = message.state ?? parsedContent.state;

// If plan came from ActionPlanner, use parameters from top-level plan state
// TODO: Can remove this after consuming nugets with #997 fixed
// If plan came from ActionPlanner, use parameters from top-level of plan
if (parsedContent.type === PlanType.Action) {
originalPlan.steps[0].parameters = originalPlan.state;
originalPlan.steps[0].parameters = originalPlan.parameters;
}

const userIntentPrefix = 'User Intent:User intent: ';
Expand Down