WeKnora deployment source with the reviewed wiki identity, summary and recovery fixes
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
Anydoc / anydoc parser engine (push) Canceled after 0s
App / Format, vet, test, and build (push) Canceled after 0s
CLI / test (macos-latest / go 1.26) (push) Canceled after 0s
CLI / test (ubuntu-latest / go 1.26) (push) Canceled after 0s
CLI / test (windows-latest / go 1.26) (push) Canceled after 0s
Build and Push Docker Image / build-ui (push) Canceled after 0s
Build and Push Docker Image / build-docreader (push) Canceled after 0s
Build and Push Docker Image / build-sandbox (push) Canceled after 0s
Build and Push Docker Image / build-app (amd64, linux/amd64, ubuntu-latest) (push) Canceled after 0s
Build and Push Docker Image / build-app (arm64, linux/arm64, ubuntu-24.04-arm) (push) Canceled after 0s
DocReader / Python tests and Go client tests (push) Canceled after 0s
Build & Publish (dsh-weknora) / Typecheck, test, pack (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (pinned) (push) Canceled after 0s
Build & Publish (dsh-weknora) / End-to-end inside dsh (latest, advisory) (push) Canceled after 0s
Frontend / Test, type-check, and build (push) Canceled after 0s
Go Lint Cache / warm lint cache (.) (push) Canceled after 0s
Go Lint Cache / warm lint cache (cli) (push) Canceled after 0s
Go Lint Cache / warm lint cache (client) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.10) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.11) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.12) (push) Canceled after 0s
Build & Publish (mcp-server) / Test (Python 3.13) (push) Canceled after 0s
Build and Push Docker Image / merge (push) Canceled after 0s
Build & Publish (dsh-weknora) / Publish to npm (push) Canceled after 0s
Build & Publish (mcp-server) / Build sdist + wheel (push) Canceled after 0s
Build & Publish (mcp-server) / Publish to PyPI (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
package modelcontext
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// HandleTable is a typed, invocation-local bidirectional mapping used when a
|
||||
// prompt needs compact handles for durable values (wiki issue iN handles,
|
||||
// ingest ref-N slug handles, c000 citation-batch handles). Handles must never
|
||||
// be persisted; Resolve converts model output back to the durable value first.
|
||||
// It is the exported word-boundary-aware wrapper over handleTable.
|
||||
type HandleTable struct {
|
||||
table *handleTable[struct{}]
|
||||
}
|
||||
|
||||
// NewHandleTable creates a handle space such as c000 (prefix=c, width=3,
|
||||
// start=0) or ref-1 (prefix=ref-, width=0, start=1).
|
||||
func NewHandleTable(prefix string, width, start int) *HandleTable {
|
||||
return &HandleTable{table: newHandleTable[struct{}](prefix, width, start)}
|
||||
}
|
||||
|
||||
// Register returns the stable handle assigned to value in this table.
|
||||
func (t *HandleTable) Register(value string) string {
|
||||
if t == nil {
|
||||
return ""
|
||||
}
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return ""
|
||||
}
|
||||
return t.table.register(value, value, struct{}{}, nil)
|
||||
}
|
||||
|
||||
// Handle returns an already registered handle without creating one.
|
||||
func (t *HandleTable) Handle(value string) (string, bool) {
|
||||
if t == nil {
|
||||
return "", false
|
||||
}
|
||||
return t.table.handleForKey(value)
|
||||
}
|
||||
|
||||
// Resolve converts a known model handle back to its durable value.
|
||||
func (t *HandleTable) Resolve(handle string) (string, bool) {
|
||||
if t == nil {
|
||||
return "", false
|
||||
}
|
||||
value, _, ok := t.table.resolve(strings.TrimSpace(handle))
|
||||
return value, ok
|
||||
}
|
||||
|
||||
func (t *HandleTable) Empty() bool {
|
||||
return t == nil || t.table.size() == 0
|
||||
}
|
||||
|
||||
func (t *HandleTable) Len() int {
|
||||
if t == nil {
|
||||
return 0
|
||||
}
|
||||
return t.table.size()
|
||||
}
|
||||
|
||||
// EncodeKnownText replaces already-registered durable values with their model
|
||||
// handles. Longer values are processed first to avoid substring shadowing.
|
||||
func (t *HandleTable) EncodeKnownText(value string) string {
|
||||
if t == nil || value == "" {
|
||||
return value
|
||||
}
|
||||
pairs := t.table.pairs()
|
||||
sort.SliceStable(pairs, func(i, j int) bool { return len(pairs[i].value) > len(pairs[j].value) })
|
||||
for _, item := range pairs {
|
||||
value = strings.ReplaceAll(value, item.value, item.handle)
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
// DecodeKnownText restores registered handles in complete text. Unlike the
|
||||
// resource codec, replacement is word-boundary-aware so short handles such as
|
||||
// i1 cannot fire inside ordinary prose tokens.
|
||||
func (t *HandleTable) DecodeKnownText(value string) string {
|
||||
if t == nil || value == "" {
|
||||
return value
|
||||
}
|
||||
pairs := t.table.pairs()
|
||||
sort.SliceStable(pairs, func(i, j int) bool { return len(pairs[i].handle) > len(pairs[j].handle) })
|
||||
for _, item := range pairs {
|
||||
if item.wordBounded == nil {
|
||||
continue
|
||||
}
|
||||
// A durable value may legally contain '$'. ReplaceAllString would
|
||||
// interpret it as a regexp expansion, so use a literal callback.
|
||||
durable := item.value
|
||||
value = item.wordBounded.ReplaceAllStringFunc(value, func(string) string { return durable })
|
||||
}
|
||||
return value
|
||||
}
|
||||
Reference in New Issue
Block a user