Skip to content

Commit c1150f3

Browse files
committed
graph view
1 parent 1da2496 commit c1150f3

17 files changed

Lines changed: 706 additions & 345 deletions

AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ Rule format:
140140
- Core AI infrastructure should stay minimal and predefined: prefer one factory that assembles known agents and known workflows, and avoid extra catalog or registry layers for skills, agents, or workflows unless a later task explicitly requires dynamic discovery.
141141
- Core AI skill and article wiring should use official Microsoft Agent Framework context primitives such as `AgentSkillsProvider` and `AIContextProvider`; do not manually concatenate embedded skill markdown into an agent system prompt.
142142
- AI, agent context, script graph extraction, and assistant action-matching paths must not use ad-hoc language heuristics for meaning, intent, or similarity. Use an available LLM path for semantic understanding; if no LLM is available, only an explicit tokenizer/vector similarity fallback is allowed, including for action search by tokenizing action descriptions and the user query into comparable token vectors.
143+
- Script graph tokenizer/vector fallback must use the tokenizer/vector primitives shipped by `ManagedCode.MarkdownLd.Kb` when available; do not keep a parallel PrompterOne-owned tokenizer implementation beside the graph library.
143144
- AI Spotlight suggestions must behave like a compact action search, not a full tool dump: show only a few top route-relevant actions before the user types, cap search matches to the best small set, and hide the suggestion list when there are no matches.
144145
- Agent tool safety metadata must classify the actual operation: ordinary revision-bound script edits are mutable but not destructive because browser history/undo owns recovery; reserve `Destructive` and required approval for operations such as deletion, irreversible replacement, publishing, recording, or external open-world effects.
145146
- Agent/MCP tool coverage is part of the feature contract: when adding a user-visible feature, action, setting, media operation, streaming operation, or editor capability, add or update the corresponding MCP-style tool descriptor in the same task, or document explicitly why the feature is not agent-callable.
@@ -152,6 +153,7 @@ Rule format:
152153
- The AI spotlight is a command/search palette plus agent chat/execution surface, not a planning screen: it should suggest route-aware commands and navigation targets while typing, send the entered prompt to the agent on submit, show execution progress only as live process/status feedback, and use a macOS Spotlight-style overlay where the underlying route remains visible with only a very light dim and no dark blurred full-page backdrop.
153154
- The AI spotlight prompt input must receive focus immediately when the spotlight opens so users can start typing without an extra click.
154155
- Script graph views must prioritize a readable writer knowledge map over decorative circular placement or raw TPS/source dumps: highlight the main/root document node, group meaningful document structure, ideas, people, themes, story references, and relationships by graph value/kind, expose node and edge hover tooltips with source detail, provide zoom/fit/layout controls, avoid noisy duplicated node-list strips under the graph, and never present source lines, WPM/pace, timing, cue, archetype, or raw TPS attribute values as primary graph nodes or primary edge labels. Graph viewing must support both a full graph-only mode and a split source/graph mode with a user-draggable divider that resizes the zones. Graph extraction must be useful to scriptwriters at a high-level glance: it should show what the text is about, how blocks and ideas connect, which references or entities recur, and where the user can jump back into the source; regex, stop-word, capitalization, keyword, and hardcoded-domain semantic heuristics are strictly forbidden. The only non-LLM fallback is an explicit user-requested tokenizer/vector similarity mode based on TikToken-style token vectors and distance calculations.
156+
- Script graph labels, details, semantic scopes, tokenizer chunks, and knowledge-graph markdown input must use compiled TPS display text from the TPS SDK, matching the clean text shown in the prompter; raw TPS source may be used for editor ranges and metadata only, not as a post-hoc string-cleaned source for visible graph prose.
155157
- The AI spotlight action inventory and agent tool inventory are related but separate surfaces: Spotlight suggestions are a macOS-style UI function search over routes and app actions, while agent MCP-style tools are the callable agent contract. Keep both fed from typed descriptors, and every supported agent tool must carry stable names, descriptions, scope, input parameters, MCP safety hints (`read-only`, `idempotent`, `destructive`, `open-world`), and an explicit approval requirement when a call can mutate app or document state.
156158
- Assistant context must be route-aware. On editor routes, the assistant context must include the current script content, cursor location, selected lines or ranges, and document metadata so rewrite actions can target the intended selection or paragraph instead of replacing the whole script.
157159
- AI document-editing tools must operate through explicit range-based contracts such as line or character insert, replace, and delete operations; whole-file regeneration is forbidden for partial rewrite requests.

Directory.Packages.props

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@
33
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
44
</PropertyGroup>
55
<ItemGroup>
6-
<PackageVersion Include="Azure.Identity" Version="1.20.0" />
6+
<PackageVersion Include="Azure.Identity" Version="1.21.0" />
77
<PackageVersion Include="bunit" Version="2.7.2" />
88
<PackageVersion Include="LLamaSharp" Version="0.26.0" />
9-
<PackageVersion Include="ManagedCode.MarkdownLd.Kb" Version="0.0.1" />
9+
<PackageVersion Include="ManagedCode.MarkdownLd.Kb" Version="0.1.0" />
1010
<PackageVersion Include="ManagedCode.MarkItDown" Version="10.0.7" />
1111
<PackageVersion Include="ManagedCode.MimeTypes" Version="10.0.1" />
1212
<PackageVersion Include="ManagedCode.Storage.Browser" Version="10.0.5" />
@@ -28,18 +28,16 @@
2828
<PackageVersion Include="Microsoft.Extensions.Localization" Version="10.0.5" />
2929
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="10.0.5" />
3030
<PackageVersion Include="Microsoft.Extensions.Logging.Configuration" Version="10.0.5" />
31-
<PackageVersion Include="Microsoft.ML.Tokenizers" Version="2.0.0" />
32-
<PackageVersion Include="Microsoft.ML.Tokenizers.Data.O200kBase" Version="2.0.0" />
33-
<PackageVersion Include="Microsoft.Playwright" Version="1.58.0" />
31+
<PackageVersion Include="Microsoft.Playwright" Version="1.59.0" />
3432
<PackageVersion Include="ModelContextProtocol.Core" Version="1.2.0" />
3533
<PackageVersion Include="OllamaSharp" Version="5.4.25" />
36-
<PackageVersion Include="Sentry.AspNetCore.Blazor.WebAssembly" Version="6.3.0" />
37-
<PackageVersion Include="Sentry" Version="6.3.0" />
34+
<PackageVersion Include="Sentry.AspNetCore.Blazor.WebAssembly" Version="6.3.1" />
35+
<PackageVersion Include="Sentry" Version="6.3.1" />
3836
<PackageVersion Include="PDFtoImage" Version="5.2.1" />
3937
<PackageVersion Include="Shouldly" Version="4.3.0" />
40-
<PackageVersion Include="TUnit" Version="1.28.7" />
41-
<PackageVersion Include="TUnit.Assertions" Version="1.28.7" />
42-
<PackageVersion Include="TUnit.Core" Version="1.28.7" />
43-
<PackageVersion Include="TUnit.Playwright" Version="1.28.7" />
38+
<PackageVersion Include="TUnit" Version="1.33.0" />
39+
<PackageVersion Include="TUnit.Assertions" Version="1.33.0" />
40+
<PackageVersion Include="TUnit.Core" Version="1.33.0" />
41+
<PackageVersion Include="TUnit.Playwright" Version="1.33.0" />
4442
</ItemGroup>
4543
</Project>

src/PrompterOne.Core/AGENTS.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ It owns TPS parsing, compilation, export, RSVP helpers, preview and workspace st
4343
- Do not let UI-specific shortcuts leak into domain parsing or RSVP behavior.
4444
- AI agent infrastructure belongs under `AI/*`; keep one focused class per concrete agent type, colocate that agent's system prompt and skill references with the agent class, prefer one factory that assembles predefined agents and workflows over separate catalog layers, and wire skills or article context through official `AgentSkillsProvider` or `AIContextProvider` support instead of hand-built prompt concatenation.
4545
- AI script graph extraction must prioritize writer-facing knowledge from the document text: themes, terms, entities, characters, concepts, claims, recurring references, and block-to-block relationships should be explicit graph concepts, while TPS/source mechanics stay metadata unless they add semantic meaning. The graph model should help a scriptwriter understand what the script is about, how ideas and blocks connect, and where to jump back into the source.
46+
- AI script graph labels, descriptions, semantic scopes, tokenizer chunks, and knowledge-graph markdown input must come from compiled TPS display text through the TPS SDK so they match the clean prompter text; raw TPS source is allowed only for source ranges and structural metadata, not post-hoc string-cleaned visible prose.
4647
- AI script graph semantic extraction must use an available LLM/chat-client path as the primary extractor. Regex, stop-word, capitalization, keyword, or hardcoded-domain semantic heuristics are strictly forbidden; when no LLM graph extraction is configured, the app may either show no semantic graph or run only an explicit user-requested tokenizer/vector similarity fallback based on `Microsoft.ML.Tokenizers` token vectors and distance calculations.
48+
- Script graph tokenizer/vector fallback must use the tokenizer/vector primitives exposed by `ManagedCode.MarkdownLd.Kb` when that package provides them; do not keep a duplicate Core-owned tokenizer implementation.
4749
- AI and agent services must not use ad-hoc language heuristics for semantic meaning, intent matching, or action similarity. Prefer LLM extraction; the only non-LLM fallback allowed for similarity or search is explicit tokenizer/vector similarity based on `Microsoft.ML.Tokenizers`.
4850
- Respect root maintainability limits. Large parser/compiler edits need explicit decomposition or documented exceptions.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using ManagedCode.Tps;
2+
using ManagedCode.Tps.Models;
3+
using System.Text;
4+
5+
namespace PrompterOne.Core.AI.Services;
6+
7+
internal sealed class ScriptKnowledgeGraphCompiledDocument
8+
{
9+
private ScriptKnowledgeGraphCompiledDocument(
10+
TpsCompilationResult compilation,
11+
string displayText,
12+
string displayMarkdown,
13+
IReadOnlyDictionary<string, string> segmentTextById,
14+
IReadOnlyDictionary<string, string> blockTextById)
15+
{
16+
Compilation = compilation;
17+
DisplayText = displayText;
18+
DisplayMarkdown = displayMarkdown;
19+
SegmentTextById = segmentTextById;
20+
BlockTextById = blockTextById;
21+
}
22+
23+
public TpsCompilationResult Compilation { get; }
24+
25+
public string DisplayText { get; }
26+
27+
public string DisplayMarkdown { get; }
28+
29+
public IReadOnlyDictionary<string, string> SegmentTextById { get; }
30+
31+
public IReadOnlyDictionary<string, string> BlockTextById { get; }
32+
33+
public static ScriptKnowledgeGraphCompiledDocument Create(string sourceContent, string? title)
34+
{
35+
var compilation = TpsRuntime.Compile(sourceContent);
36+
var segmentTextById = compilation.Script.Segments.ToDictionary(
37+
static segment => segment.Id,
38+
static segment => BuildWordText(segment.Words),
39+
StringComparer.Ordinal);
40+
var blockTextById = compilation.Script.Segments
41+
.SelectMany(static segment => segment.Blocks)
42+
.ToDictionary(
43+
static block => block.Id,
44+
static block => BuildWordText(block.Words),
45+
StringComparer.Ordinal);
46+
var displayText = BuildWordText(compilation.Script.Words);
47+
var displayMarkdown = BuildDisplayMarkdown(compilation.Script, title);
48+
49+
return new ScriptKnowledgeGraphCompiledDocument(
50+
compilation,
51+
displayText,
52+
displayMarkdown,
53+
segmentTextById,
54+
blockTextById);
55+
}
56+
57+
public string GetSegmentText(string segmentId) =>
58+
SegmentTextById.TryGetValue(segmentId, out var text) ? text : string.Empty;
59+
60+
public string GetBlockText(string blockId) =>
61+
BlockTextById.TryGetValue(blockId, out var text) ? text : string.Empty;
62+
63+
private static string BuildDisplayMarkdown(CompiledScript script, string? title)
64+
{
65+
var builder = new StringBuilder();
66+
if (!string.IsNullOrWhiteSpace(title))
67+
{
68+
builder.Append("# ").AppendLine(title.Trim());
69+
}
70+
71+
foreach (var segment in script.Segments)
72+
{
73+
builder.Append("## ").AppendLine(segment.Name);
74+
if (segment.Blocks.Count == 0)
75+
{
76+
AppendScopeText(builder, BuildWordText(segment.Words));
77+
continue;
78+
}
79+
80+
foreach (var block in segment.Blocks)
81+
{
82+
builder.Append("### ").AppendLine(block.Name);
83+
AppendScopeText(builder, BuildWordText(block.Words));
84+
}
85+
}
86+
87+
return builder.ToString().Trim();
88+
}
89+
90+
private static void AppendScopeText(StringBuilder builder, string text)
91+
{
92+
if (string.IsNullOrWhiteSpace(text))
93+
{
94+
return;
95+
}
96+
97+
builder.AppendLine(text).AppendLine();
98+
}
99+
100+
private static string BuildWordText(IEnumerable<CompiledWord> words) =>
101+
string.Join(
102+
' ',
103+
words
104+
.Where(static word => word.Metadata.IsPause == false)
105+
.Select(static word => word.CleanText)
106+
.Where(static text => !string.IsNullOrWhiteSpace(text)));
107+
}

src/PrompterOne.Core/AI/Services/ScriptKnowledgeGraphDocumentBuilder.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ public static void AddDocumentGraph(
1212
string containsEdgeLabel,
1313
ScriptKnowledgeGraphBuildRequest request,
1414
string content,
15+
string displayContent,
1516
ICollection<ScriptKnowledgeGraphSemanticScope> scopes,
1617
IDictionary<string, ScriptKnowledgeGraphNode> nodes,
1718
IDictionary<string, ScriptKnowledgeGraphEdge> edges,
@@ -28,7 +29,7 @@ public static void AddDocumentGraph(
2829
["source"] = "script",
2930
["documentId"] = request.DocumentId ?? string.Empty
3031
});
31-
scopes.Add(new ScriptKnowledgeGraphSemanticScope(documentNodeId, "Document", content));
32+
scopes.Add(new ScriptKnowledgeGraphSemanticScope(documentNodeId, "Document", displayContent));
3233

3334
AddSectionNodes(documentNodeId, containsEdgeLabel, content, nodes, edges, ranges);
3435
}

src/PrompterOne.Core/AI/Services/ScriptKnowledgeGraphService.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,13 @@ public async Task<ScriptKnowledgeGraphArtifact> BuildAsync(
2020
ArgumentNullException.ThrowIfNull(request);
2121

2222
var content = request.Content ?? string.Empty;
23+
var compiledDocument = ScriptKnowledgeGraphCompiledDocument.Create(content, request.Title);
2324
var pipeline = new MarkdownKnowledgePipeline();
2425
var kbResult = await pipeline
25-
.BuildFromMarkdownAsync(content, CreateSourcePath(request.DocumentId), cancellationToken: cancellationToken)
26+
.BuildFromMarkdownAsync(
27+
compiledDocument.DisplayMarkdown,
28+
CreateSourcePath(request.DocumentId),
29+
cancellationToken: cancellationToken)
2630
.ConfigureAwait(false);
2731

2832
var nodes = new Dictionary<string, ScriptKnowledgeGraphNode>(StringComparer.Ordinal);
@@ -35,6 +39,7 @@ public async Task<ScriptKnowledgeGraphArtifact> BuildAsync(
3539
ContainsEdgeLabel,
3640
request,
3741
content,
42+
compiledDocument.DisplayText,
3843
semanticScopes,
3944
nodes,
4045
edges,
@@ -43,16 +48,32 @@ public async Task<ScriptKnowledgeGraphArtifact> BuildAsync(
4348
DocumentNodeId,
4449
ContainsEdgeLabel,
4550
content,
51+
compiledDocument,
4652
semanticScopes,
4753
nodes,
4854
edges,
4955
ranges);
5056
AddKnowledgeBankGraph(kbResult.Graph.ToSnapshot(), content, nodes, edges, ranges);
51-
var semanticStatus = await TryAddModelSemanticGraphAsync(request, content, semanticScopes, nodes, edges, ranges, cancellationToken)
57+
var semanticStatus = await TryAddModelSemanticGraphAsync(
58+
request,
59+
compiledDocument.DisplayMarkdown,
60+
semanticScopes,
61+
nodes,
62+
edges,
63+
ranges,
64+
cancellationToken)
5265
.ConfigureAwait(false);
5366
if (semanticStatus != ScriptKnowledgeGraphSemanticStatus.Model &&
5467
request.SemanticMode == ScriptKnowledgeGraphSemanticMode.TokenizerSimilarity &&
55-
_tokenizerSimilarityExtractor.AddTokenizerSimilarity(content, semanticScopes, nodes, edges, ranges))
68+
await _tokenizerSimilarityExtractor
69+
.AddTokenizerSimilarityAsync(
70+
content,
71+
compiledDocument.DisplayMarkdown,
72+
nodes,
73+
edges,
74+
ranges,
75+
cancellationToken)
76+
.ConfigureAwait(false))
5677
{
5778
semanticStatus = ScriptKnowledgeGraphSemanticStatus.TokenizerSimilarity;
5879
}

0 commit comments

Comments
 (0)