@dxos/assistant 0.14.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/ExecutionGraph.mjs.map +1 -1
- package/dist/lib/chunk-Agent.mjs +202 -0
- package/dist/lib/chunk-Agent.mjs.map +1 -0
- package/dist/lib/chunk-AiContext.mjs +462 -0
- package/dist/lib/chunk-AiContext.mjs.map +1 -0
- package/dist/lib/chunk-AiRequest.mjs.map +1 -1
- package/dist/lib/chunk-AiSession.mjs +2 -2
- package/dist/lib/chunk-AiSession.mjs.map +1 -1
- package/dist/lib/chunk-Alarm.mjs +37 -0
- package/dist/lib/chunk-Alarm.mjs.map +1 -0
- package/dist/lib/chunk-Chat.mjs +258 -0
- package/dist/lib/chunk-Chat.mjs.map +1 -0
- package/dist/lib/chunk-Harness.mjs +4 -4
- package/dist/lib/chunk-Harness.mjs.map +1 -1
- package/dist/lib/chunk-SessionLink.mjs +20 -0
- package/dist/lib/chunk-SessionLink.mjs.map +1 -0
- package/dist/lib/chunk-SkillHooks.mjs +47 -0
- package/dist/lib/chunk-SkillHooks.mjs.map +1 -0
- package/dist/lib/extraction.mjs.map +1 -1
- package/dist/lib/index.mjs +6 -6
- package/dist/lib/index.mjs.map +1 -1
- package/dist/lib/request/AiRequest.mjs +1 -2
- package/dist/lib/session/AiContext.mjs +1 -462
- package/dist/lib/session/AiSession.mjs +1 -2
- package/dist/lib/session/Alarm.mjs +1 -37
- package/dist/lib/session/Harness.mjs +1 -2
- package/dist/lib/session/SessionLink.mjs +1 -20
- package/dist/lib/session/SkillHooks.mjs +1 -47
- package/dist/lib/types/Agent.mjs +1 -202
- package/dist/lib/types/Chat.mjs +1 -258
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +23 -23
- package/src/request/AiRequest.test.ts +1 -1
- package/src/types/Agent.ts +1 -1
- package/dist/lib/session/AiContext.mjs.map +0 -1
- package/dist/lib/session/Alarm.mjs.map +0 -1
- package/dist/lib/session/SessionLink.mjs.map +0 -1
- package/dist/lib/session/SkillHooks.mjs.map +0 -1
- package/dist/lib/types/Agent.mjs.map +0 -1
- package/dist/lib/types/Chat.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extraction.mjs","names":[],"sources":["../../src/extraction/quotes.ts","../../src/extraction/extraction-llm-function/proper-noun-extraction.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { type Database, Filter, Query } from '@dxos/echo';\nimport { EID, EntityId } from '@dxos/keys';\n\nexport const ReferencedQuotes = Schema.Struct({\n references: Schema.Array(\n Schema.Struct({\n id: Schema.String,\n quote: Schema.String, // TODO(burdon): Quote?\n }),\n )\n .pipe(Schema.mutable)\n .annotate({\n // TODO(burdon): Does this description make sense?\n description: `\n The references to the context objects that are mentioned in the transcript. \n Quote should match the original transcript text exactly, while id is the id of the context object.\n `,\n }),\n});\nexport type ReferencedQuotes = Schema.Schema.Type<typeof ReferencedQuotes>;\n\nexport type FindReferencesOptions = {\n /** Search backend. Full-text matches proper nouns precisely; vector matches semantically. */\n searchKind?: 'full-text' | 'vector';\n};\n\n/**\n * Finds the best-matching context object for each noun and returns it as a reference.\n */\nexport const findReferences = async (\n nouns: string[],\n db: Database.Database,\n { searchKind = 'full-text' }: FindReferencesOptions = {},\n): Promise<ReferencedQuotes> => {\n // Deduplicate and process longer nouns first: `insertReferences` rewrites case-insensitive\n // substrings, so a repeated or shorter overlapping noun would re-replace already-linked text and\n // produce nested/broken markdown links.\n const normalizedNouns = Array.from(new Set(nouns.map((noun) => noun.trim()).filter((noun) => noun.length > 0))).sort(\n (leftNoun, rightNoun) => rightNoun.length - leftNoun.length,\n );\n\n const references = await Promise.all(\n normalizedNouns.map(async (noun) => {\n const objects = await db.query(Query.select(Filter.text(noun, { type: searchKind }))).run();\n return objects.length > 0 ? [{ id: objects[0].id.toString(), quote: noun }] : [];\n }),\n );\n return { references: references.flat() };\n};\n\n/**\n * Finds and replaces all quotes with DXNs references.\n */\n// TODO(dmaretskyi): Lookup and verifiy ids from provided context.\nexport const insertReferences = (text: string, quotes: ReferencedQuotes): string => {\n // Process longer quotes first so e.g. \"Sarah Johnson\" is linked before \"Sarah\". Combined with the\n // link-aware replacement below this stops a shorter or overlapping quote from rewriting text that\n // is already part of an inserted link (which would produce nested `[[..](..)](..)` markdown).\n const references = quotes.references\n .filter((quote) => EntityId.isValid(quote.id))\n .sort((left, right) => right.quote.length - left.quote.length);\n\n for (const quote of references) {\n // Case-insensitive match of the (regex-escaped) quote.\n const regex = new RegExp(quote.quote.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'gi');\n text = replaceOutsideLinks(text, regex, `[${quote.quote}](${EID.make({ entityId: quote.id })})`);\n }\n\n return text;\n};\n\nconst MARKDOWN_LINK = /\\[[^\\]]*\\]\\([^)]*\\)/g;\n\n/** Applies a replacement to every span of `text` that is not already inside a `[label](url)` link. */\nconst replaceOutsideLinks = (text: string, regex: RegExp, replacement: string): string => {\n let result = '';\n let plainStart = 0;\n for (const link of text.matchAll(MARKDOWN_LINK)) {\n const index = link.index ?? 0;\n result += text.slice(plainStart, index).replace(regex, replacement) + link[0];\n plainStart = index + link[0].length;\n }\n return result + text.slice(plainStart).replace(regex, replacement);\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport * as LanguageModel from 'effect/ai/LanguageModel';\nimport * as Effect from 'effect/Effect';\nimport * as Schema from 'effect/Schema';\n\nimport { AiService } from '@dxos/ai';\nimport { type Database, Obj } from '@dxos/echo';\nimport { Message } from '@dxos/types';\n\nimport { findReferences, insertReferences } from '../quotes.ts';\n\nconst EXTRACTION_MODEL = 'com.anthropic.model.claude-haiku-4-5.default';\n\n/**\n * Proper nouns extracted from transcript text.\n */\nexport const ProperNouns = Schema.Struct({\n properNouns: Schema.Array(Schema.String).annotate({\n description: 'Proper nouns (names of people, organizations, places, products) mentioned in the text.',\n }),\n});\nexport type ProperNouns = Schema.Schema.Type<typeof ProperNouns>;\n\n/**\n * Extracts proper nouns from transcript text using a small LLM (Haiku). Provides the LanguageModel\n * internally so the residual requirement is just {@link AiService.AiService}.\n */\nexport const extractProperNouns = (text: string) =>\n Effect.gen(function* () {\n const { value } = yield* Effect.scoped(\n LanguageModel.generateObject({\n schema: ProperNouns,\n prompt: [\n 'Extract every proper noun (people, organizations, places, products) mentioned in the transcript text below.',\n 'Return only the surface strings exactly as they appear. Exclude common nouns and pronouns.',\n '',\n 'Transcript:',\n text,\n ].join('\\n'),\n }),\n );\n\n // Drop short tokens (e.g. \"IT\"): insertReferences replaces case-insensitive substrings, so a\n // short noun would match inside unrelated words (\"secur[IT]y\") and corrupt neighbouring links.\n return value.properNouns.map((noun) => noun.trim()).filter((noun) => noun.length >= 3);\n }).pipe(Effect.provide(AiService.languageModel(EXTRACTION_MODEL)));\n\n/**\n * Enriches a transcript message: for each transcript block, extracts proper nouns, links them to\n * objects in the space via full-text search, and rewrites the text with `[noun](dxn)` references.\n * Requires {@link AiService.AiService}; takes the space database handle.\n */\nexport const enrichTranscriptMessage = (message: Message.Message, { db }: { db: Database.Database }) =>\n Effect.gen(function* () {\n const blocks = yield* Effect.forEach(message.blocks, (block) =>\n Effect.gen(function* () {\n if (block._tag !== 'transcript') {\n return block;\n }\n\n const nouns = yield* extractProperNouns(block.text);\n const references = yield* Effect.promise(() => findReferences([...nouns], db));\n return { ...block, text: insertReferences(block.text, references) };\n }),\n );\n\n // Preserve the message identity and metadata; enrichment only rewrites transcript block text.\n return Obj.make(Message.Message, {\n id: message.id,\n sender: message.sender,\n created: message.created,\n properties: message.properties,\n blocks,\n });\n });\n"],"mappings":";;;;;;;;AASA,IAAa,mBAAmB,OAAO,OAAO,EAC5C,YAAY,OAAO,MACjB,OAAO,OAAO;CACZ,IAAI,OAAO;CACX,OAAO,OAAO;AAChB,CAAC,CACH,CAAA,CACG,KAAK,OAAO,OAAO,CAAA,CACnB,SAAS,EAER,aAAa;;;MAIf,CAAC,EACL,CAAC;;;;AAWD,IAAa,iBAAiB,OAC5B,OACA,IACA,EAAE,aAAa,gBAAuC,CAAC,MACzB;CAI9B,MAAM,kBAAkB,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,QAAQ,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,MAC7G,UAAU,cAAc,UAAU,SAAS,SAAS,MACvD;CAQA,OAAO,EAAE,aAAY,MANI,QAAQ,IAC/B,gBAAgB,IAAI,OAAO,SAAS;EAClC,MAAM,UAAU,MAAM,GAAG,MAAM,MAAM,OAAO,OAAO,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI;EAC1F,OAAO,QAAQ,SAAS,IAAI,CAAC;GAAE,IAAI,QAAQ,EAAE,CAAC,GAAG,SAAS;GAAG,OAAO;EAAK,CAAC,IAAI,CAAC;CACjF,CAAC,CACH,EAAA,CACgC,KAAK,EAAE;AACzC;;;;AAMA,IAAa,oBAAoB,MAAc,WAAqC;CAIlF,MAAM,aAAa,OAAO,WACvB,QAAQ,UAAU,SAAS,QAAQ,MAAM,EAAE,CAAC,CAAA,CAC5C,MAAM,MAAM,UAAU,MAAM,MAAM,SAAS,KAAK,MAAM,MAAM;CAE/D,KAAK,MAAM,SAAS,YAAY;EAE9B,MAAM,QAAQ,IAAI,OAAO,MAAM,MAAM,QAAQ,uBAAuB,MAAM,GAAG,IAAI;EACjF,OAAO,oBAAoB,MAAM,OAAO,IAAI,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"extraction.mjs","names":["EID"],"sources":["../../src/extraction/quotes.ts","../../src/extraction/extraction-llm-function/proper-noun-extraction.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { type Database, Filter, Query } from '@dxos/echo';\nimport { EID, EntityId } from '@dxos/keys';\n\nexport const ReferencedQuotes = Schema.Struct({\n references: Schema.Array(\n Schema.Struct({\n id: Schema.String,\n quote: Schema.String, // TODO(burdon): Quote?\n }),\n )\n .pipe(Schema.mutable)\n .annotate({\n // TODO(burdon): Does this description make sense?\n description: `\n The references to the context objects that are mentioned in the transcript. \n Quote should match the original transcript text exactly, while id is the id of the context object.\n `,\n }),\n});\nexport type ReferencedQuotes = Schema.Schema.Type<typeof ReferencedQuotes>;\n\nexport type FindReferencesOptions = {\n /** Search backend. Full-text matches proper nouns precisely; vector matches semantically. */\n searchKind?: 'full-text' | 'vector';\n};\n\n/**\n * Finds the best-matching context object for each noun and returns it as a reference.\n */\nexport const findReferences = async (\n nouns: string[],\n db: Database.Database,\n { searchKind = 'full-text' }: FindReferencesOptions = {},\n): Promise<ReferencedQuotes> => {\n // Deduplicate and process longer nouns first: `insertReferences` rewrites case-insensitive\n // substrings, so a repeated or shorter overlapping noun would re-replace already-linked text and\n // produce nested/broken markdown links.\n const normalizedNouns = Array.from(new Set(nouns.map((noun) => noun.trim()).filter((noun) => noun.length > 0))).sort(\n (leftNoun, rightNoun) => rightNoun.length - leftNoun.length,\n );\n\n const references = await Promise.all(\n normalizedNouns.map(async (noun) => {\n const objects = await db.query(Query.select(Filter.text(noun, { type: searchKind }))).run();\n return objects.length > 0 ? [{ id: objects[0].id.toString(), quote: noun }] : [];\n }),\n );\n return { references: references.flat() };\n};\n\n/**\n * Finds and replaces all quotes with DXNs references.\n */\n// TODO(dmaretskyi): Lookup and verifiy ids from provided context.\nexport const insertReferences = (text: string, quotes: ReferencedQuotes): string => {\n // Process longer quotes first so e.g. \"Sarah Johnson\" is linked before \"Sarah\". Combined with the\n // link-aware replacement below this stops a shorter or overlapping quote from rewriting text that\n // is already part of an inserted link (which would produce nested `[[..](..)](..)` markdown).\n const references = quotes.references\n .filter((quote) => EntityId.isValid(quote.id))\n .sort((left, right) => right.quote.length - left.quote.length);\n\n for (const quote of references) {\n // Case-insensitive match of the (regex-escaped) quote.\n const regex = new RegExp(quote.quote.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'), 'gi');\n text = replaceOutsideLinks(text, regex, `[${quote.quote}](${EID.make({ entityId: quote.id })})`);\n }\n\n return text;\n};\n\nconst MARKDOWN_LINK = /\\[[^\\]]*\\]\\([^)]*\\)/g;\n\n/** Applies a replacement to every span of `text` that is not already inside a `[label](url)` link. */\nconst replaceOutsideLinks = (text: string, regex: RegExp, replacement: string): string => {\n let result = '';\n let plainStart = 0;\n for (const link of text.matchAll(MARKDOWN_LINK)) {\n const index = link.index ?? 0;\n result += text.slice(plainStart, index).replace(regex, replacement) + link[0];\n plainStart = index + link[0].length;\n }\n return result + text.slice(plainStart).replace(regex, replacement);\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport * as LanguageModel from 'effect/ai/LanguageModel';\nimport * as Effect from 'effect/Effect';\nimport * as Schema from 'effect/Schema';\n\nimport { AiService } from '@dxos/ai';\nimport { type Database, Obj } from '@dxos/echo';\nimport { Message } from '@dxos/types';\n\nimport { findReferences, insertReferences } from '../quotes.ts';\n\nconst EXTRACTION_MODEL = 'com.anthropic.model.claude-haiku-4-5.default';\n\n/**\n * Proper nouns extracted from transcript text.\n */\nexport const ProperNouns = Schema.Struct({\n properNouns: Schema.Array(Schema.String).annotate({\n description: 'Proper nouns (names of people, organizations, places, products) mentioned in the text.',\n }),\n});\nexport type ProperNouns = Schema.Schema.Type<typeof ProperNouns>;\n\n/**\n * Extracts proper nouns from transcript text using a small LLM (Haiku). Provides the LanguageModel\n * internally so the residual requirement is just {@link AiService.AiService}.\n */\nexport const extractProperNouns = (text: string) =>\n Effect.gen(function* () {\n const { value } = yield* Effect.scoped(\n LanguageModel.generateObject({\n schema: ProperNouns,\n prompt: [\n 'Extract every proper noun (people, organizations, places, products) mentioned in the transcript text below.',\n 'Return only the surface strings exactly as they appear. Exclude common nouns and pronouns.',\n '',\n 'Transcript:',\n text,\n ].join('\\n'),\n }),\n );\n\n // Drop short tokens (e.g. \"IT\"): insertReferences replaces case-insensitive substrings, so a\n // short noun would match inside unrelated words (\"secur[IT]y\") and corrupt neighbouring links.\n return value.properNouns.map((noun) => noun.trim()).filter((noun) => noun.length >= 3);\n }).pipe(Effect.provide(AiService.languageModel(EXTRACTION_MODEL)));\n\n/**\n * Enriches a transcript message: for each transcript block, extracts proper nouns, links them to\n * objects in the space via full-text search, and rewrites the text with `[noun](dxn)` references.\n * Requires {@link AiService.AiService}; takes the space database handle.\n */\nexport const enrichTranscriptMessage = (message: Message.Message, { db }: { db: Database.Database }) =>\n Effect.gen(function* () {\n const blocks = yield* Effect.forEach(message.blocks, (block) =>\n Effect.gen(function* () {\n if (block._tag !== 'transcript') {\n return block;\n }\n\n const nouns = yield* extractProperNouns(block.text);\n const references = yield* Effect.promise(() => findReferences([...nouns], db));\n return { ...block, text: insertReferences(block.text, references) };\n }),\n );\n\n // Preserve the message identity and metadata; enrichment only rewrites transcript block text.\n return Obj.make(Message.Message, {\n id: message.id,\n sender: message.sender,\n created: message.created,\n properties: message.properties,\n blocks,\n });\n });\n"],"mappings":"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"}
|
package/dist/lib/index.mjs
CHANGED
|
@@ -2,13 +2,13 @@ import { a as formatUserPrompt, c as decodeToolParameters, d as makeToolExecutio
|
|
|
2
2
|
import { n as AiModelError, r as HarnessContextError, t as AiAssistantError } from "./chunk-errors.mjs";
|
|
3
3
|
import { ExecutionGraph } from "./ExecutionGraph.mjs";
|
|
4
4
|
import { o as createToolkit, t as AiSession_exports } from "./chunk-AiSession.mjs";
|
|
5
|
-
import { t as AiContext_exports } from "./
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
5
|
+
import { t as AiContext_exports } from "./chunk-AiContext.mjs";
|
|
6
|
+
import { n as Chat_exports } from "./chunk-Chat.mjs";
|
|
7
|
+
import { n as Alarm_exports } from "./chunk-Alarm.mjs";
|
|
8
|
+
import { n as SessionLink_exports } from "./chunk-SessionLink.mjs";
|
|
9
9
|
import { _ as SessionStore, b as isQueued, g as QueuedAnnotation, h as InFlightAnnotation, m as ConsumedAnnotation, n as Harness_exports, v as isConsumed, y as isInFlight } from "./chunk-Harness.mjs";
|
|
10
|
-
import { t as SkillHooks_exports } from "./
|
|
11
|
-
import {
|
|
10
|
+
import { t as SkillHooks_exports } from "./chunk-SkillHooks.mjs";
|
|
11
|
+
import { n as Agent_exports } from "./chunk-Agent.mjs";
|
|
12
12
|
import * as Effect from "effect/Effect";
|
|
13
13
|
import * as Schema from "effect/Schema";
|
|
14
14
|
import { log } from "@dxos/log";
|
package/dist/lib/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/util/diff.ts","../../src/util/error-handling.ts","../../src/session/harness-control.ts","../../src/templates/system.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { next as A, type Doc as AutomergeDoc } from '@automerge/automerge';\n\nimport { toCursorRange } from '@dxos/echo-client';\nimport { Doc } from '@dxos/echo-doc';\nimport { log } from '@dxos/log';\nimport { isNonNullable } from '@dxos/util';\n\n// Relevant info:\n// https://github.com/Minahil-official/GPT-4.1-Promting-Guide?tab=readme-ov-file#-apply-patch-tool-format-v4a-diff\n\n// TODO(burdon): Anthropic only.\n// https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/text-editor-tool#example-str-replace-command\n// AI_TOOL_NOT_FOUND: str_replace_based_edit_tool\n// 'str_replace_based_edit_tool',\n\n// TOOD(burdon): Support append to end (no \"-\").\n\nexport type Diff = {\n match: string;\n replace: string;\n};\n\n/**\n * Convert a list of diffs into a list of operations.\n */\nexport const reduceDiffs = (diffs: readonly string[]): Diff[] => {\n return diffs.reduce<Diff[]>((acc, diff) => {\n const current = acc[acc.length - 1];\n const [op, ...rest] = diff.split(' ');\n switch (op) {\n case '-': {\n if (current && !current.match) {\n current.match += rest.join(' ');\n } else {\n acc.push({ match: rest.join(' '), replace: '' });\n }\n return acc;\n }\n case '+': {\n if (current && !current.replace) {\n current.replace += rest.join(' ');\n } else {\n acc.push({ match: '', replace: rest.join(' ') });\n }\n return acc;\n }\n default: {\n throw new Error(`Invalid diff format: each line must start with \"- \" or \"+ \", got: ${JSON.stringify(diff)}`);\n }\n }\n }, []);\n};\n\n/**\n * Resolves text diffs against the accessor's current value into cursor-anchored replacements.\n */\nexport const computeDiffsWithCursors = <T>(accessor: Doc.Accessor<T>, diffs: readonly string[]) => {\n return reduceDiffs(diffs)\n .map((diff) => {\n const text = Doc.getValue<string>(accessor);\n const idx = text.indexOf(diff.match);\n if (idx !== -1) {\n return { cursor: toCursorRange(accessor, idx, idx + diff.match.length), text: diff.replace };\n }\n })\n .filter(isNonNullable);\n};\n\n/**\n * Applies text diffs to the accessor-backed document and returns the resulting string.\n */\nexport const applyDiffs = <T>(\n accessor: Doc.Accessor<T>,\n diffs: readonly string[],\n { errorOnNotFound = false }: { errorOnNotFound?: boolean } = {},\n): string => {\n for (const diff of reduceDiffs(diffs)) {\n accessor.handle.change((doc: AutomergeDoc<T>) => {\n const text = Doc.getValue<string>(accessor);\n const idx = text.indexOf(diff.match);\n if (idx !== -1) {\n // TODO(burdon): Replace smallest substring.\n // NOTE: This only replaces the first match.\n A.splice(doc, accessor.path as A.Prop[], idx, diff.match.length, diff.replace);\n } else {\n if (errorOnNotFound) {\n throw new Error(`Diff not found: ${diff.match}`);\n } else {\n log.warn('diff not found', diff);\n }\n }\n });\n }\n\n return Doc.getValue<string>(accessor);\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport * as AiError from 'effect/ai/AiError';\nimport * as Effect from 'effect/Effect';\nimport * as Schema from 'effect/Schema';\n\nimport { AiModelError } from './errors.ts';\n\nconst AnthropicErrorResponse = Schema.Struct({\n type: Schema.Literal('error'),\n error: Schema.Struct({\n type: Schema.String,\n message: Schema.String,\n }),\n});\n\n// TODO(dmaretskyi): Needs rework.\nexport const mapAiError = (err: AiError.AiError): Effect.Effect<AiError.AiError> =>\n Effect.gen(function* () {\n const cause = err.reason;\n if (cause._tag === 'UnknownError' && cause.http?.body !== undefined) {\n const body = yield* Effect.succeed(JSON.parse(cause.http.body)).pipe(\n Effect.flatMap(Schema.decodeUnknownEffect(AnthropicErrorResponse)),\n );\n\n const parsedCause = new AiModelError({\n message: body.error.message,\n context: { model: 'anthropic', type: body.error.type },\n });\n\n return new AiError.AiError({\n module: err.module,\n method: err.method,\n reason: new AiError.UnknownError({\n description: body.error.message,\n metadata: { type: body.error.type, cause: String(parsedCause) },\n }),\n });\n }\n return err;\n }).pipe(Effect.catch(() => Effect.succeed(err)));\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Rpc from 'effect/rpc/Rpc';\nimport * as RpcGroup from 'effect/rpc/RpcGroup';\nimport * as Schema from 'effect/Schema';\n\nimport { ContentBlock } from '@dxos/types';\n\n/**\n * Typed control surface on the live host process that owns a conversation's harness.\n *\n * The same group is declared as the agent process's `rpcs` (so its handlers run on the host's\n * server fiber, writing queued messages and alarms to the conversation feed) and used by {@link HarnessService}\n * Tier B to dispatch over the discovered host's `Handle.rpc` — keeping both ends on one contract.\n */\nexport const HarnessControl = RpcGroup.make(\n Rpc.make('setAlarm', {\n payload: Schema.Struct({ at: Schema.DateTimeUtc, message: Schema.NullOr(Schema.String) }),\n success: Schema.Void,\n }),\n Rpc.make('enqueueMessage', {\n payload: Schema.Struct({ content: Schema.Array(ContentBlock.Any) }),\n success: Schema.Void,\n }),\n);\n\n/** Union of the RPCs declared in {@link HarnessControl}. */\nexport type HarnessControlRpcs = RpcGroup.Rpcs<typeof HarnessControl>;\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport defaultsDeep from 'lodash.defaultsdeep';\n\nimport { Model } from '@dxos/ai';\nimport * as Template from '@dxos/compute/Template';\n// Text is referenced in the inferred type of 'templates' (via Template.make → Template.Template.source → Ref.Ref(Text.Text));\n// the import lets TypeScript name it in the emitted .d.ts.\n// eslint-disable-next-line unused-imports/no-unused-imports\nimport { type Text } from '@dxos/schema';\n\nimport FORMAT from './instructions/format.tpl?raw';\nimport SYSTEM from './instructions/system.tpl?raw';\n\n/**\n * System template variables.\n */\nexport type SystemPromptOptions = Model.Capabilities & {\n DATETIME: string;\n};\n\n/**\n * Base system prompt.\n * NOTE: This contains protocol instructions that can not be dynamically edited.\n */\nexport const createSystemPrompt = (options: Partial<SystemPromptOptions> = {}) =>\n Template.process<SystemPromptOptions>(\n FORMAT,\n defaultsDeep(options, {\n DATETIME: new Date().toISOString(),\n }),\n );\n\n/**\n * NOTE: We are forbidden from accessing randomness at model level in cloudflare, so we have to have pre-generated ids.\n */\nconst SYSTEM_ID = '01K2J2FZWH39F55CS7B26GP1Q3';\n\nexport const templates = {\n system: Template.make({\n id: SYSTEM_ID,\n source: SYSTEM,\n }),\n};\n"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["FORMAT","SYSTEM"],"sources":["../../src/util/diff.ts","../../src/util/error-handling.ts","../../src/session/harness-control.ts","../../src/templates/system.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { next as A, type Doc as AutomergeDoc } from '@automerge/automerge';\n\nimport { toCursorRange } from '@dxos/echo-client';\nimport { Doc } from '@dxos/echo-doc';\nimport { log } from '@dxos/log';\nimport { isNonNullable } from '@dxos/util';\n\n// Relevant info:\n// https://github.com/Minahil-official/GPT-4.1-Promting-Guide?tab=readme-ov-file#-apply-patch-tool-format-v4a-diff\n\n// TODO(burdon): Anthropic only.\n// https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/text-editor-tool#example-str-replace-command\n// AI_TOOL_NOT_FOUND: str_replace_based_edit_tool\n// 'str_replace_based_edit_tool',\n\n// TOOD(burdon): Support append to end (no \"-\").\n\nexport type Diff = {\n match: string;\n replace: string;\n};\n\n/**\n * Convert a list of diffs into a list of operations.\n */\nexport const reduceDiffs = (diffs: readonly string[]): Diff[] => {\n return diffs.reduce<Diff[]>((acc, diff) => {\n const current = acc[acc.length - 1];\n const [op, ...rest] = diff.split(' ');\n switch (op) {\n case '-': {\n if (current && !current.match) {\n current.match += rest.join(' ');\n } else {\n acc.push({ match: rest.join(' '), replace: '' });\n }\n return acc;\n }\n case '+': {\n if (current && !current.replace) {\n current.replace += rest.join(' ');\n } else {\n acc.push({ match: '', replace: rest.join(' ') });\n }\n return acc;\n }\n default: {\n throw new Error(`Invalid diff format: each line must start with \"- \" or \"+ \", got: ${JSON.stringify(diff)}`);\n }\n }\n }, []);\n};\n\n/**\n * Resolves text diffs against the accessor's current value into cursor-anchored replacements.\n */\nexport const computeDiffsWithCursors = <T>(accessor: Doc.Accessor<T>, diffs: readonly string[]) => {\n return reduceDiffs(diffs)\n .map((diff) => {\n const text = Doc.getValue<string>(accessor);\n const idx = text.indexOf(diff.match);\n if (idx !== -1) {\n return { cursor: toCursorRange(accessor, idx, idx + diff.match.length), text: diff.replace };\n }\n })\n .filter(isNonNullable);\n};\n\n/**\n * Applies text diffs to the accessor-backed document and returns the resulting string.\n */\nexport const applyDiffs = <T>(\n accessor: Doc.Accessor<T>,\n diffs: readonly string[],\n { errorOnNotFound = false }: { errorOnNotFound?: boolean } = {},\n): string => {\n for (const diff of reduceDiffs(diffs)) {\n accessor.handle.change((doc: AutomergeDoc<T>) => {\n const text = Doc.getValue<string>(accessor);\n const idx = text.indexOf(diff.match);\n if (idx !== -1) {\n // TODO(burdon): Replace smallest substring.\n // NOTE: This only replaces the first match.\n A.splice(doc, accessor.path as A.Prop[], idx, diff.match.length, diff.replace);\n } else {\n if (errorOnNotFound) {\n throw new Error(`Diff not found: ${diff.match}`);\n } else {\n log.warn('diff not found', diff);\n }\n }\n });\n }\n\n return Doc.getValue<string>(accessor);\n};\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport * as AiError from 'effect/ai/AiError';\nimport * as Effect from 'effect/Effect';\nimport * as Schema from 'effect/Schema';\n\nimport { AiModelError } from './errors.ts';\n\nconst AnthropicErrorResponse = Schema.Struct({\n type: Schema.Literal('error'),\n error: Schema.Struct({\n type: Schema.String,\n message: Schema.String,\n }),\n});\n\n// TODO(dmaretskyi): Needs rework.\nexport const mapAiError = (err: AiError.AiError): Effect.Effect<AiError.AiError> =>\n Effect.gen(function* () {\n const cause = err.reason;\n if (cause._tag === 'UnknownError' && cause.http?.body !== undefined) {\n const body = yield* Effect.succeed(JSON.parse(cause.http.body)).pipe(\n Effect.flatMap(Schema.decodeUnknownEffect(AnthropicErrorResponse)),\n );\n\n const parsedCause = new AiModelError({\n message: body.error.message,\n context: { model: 'anthropic', type: body.error.type },\n });\n\n return new AiError.AiError({\n module: err.module,\n method: err.method,\n reason: new AiError.UnknownError({\n description: body.error.message,\n metadata: { type: body.error.type, cause: String(parsedCause) },\n }),\n });\n }\n return err;\n }).pipe(Effect.catch(() => Effect.succeed(err)));\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport * as Rpc from 'effect/rpc/Rpc';\nimport * as RpcGroup from 'effect/rpc/RpcGroup';\nimport * as Schema from 'effect/Schema';\n\nimport { ContentBlock } from '@dxos/types';\n\n/**\n * Typed control surface on the live host process that owns a conversation's harness.\n *\n * The same group is declared as the agent process's `rpcs` (so its handlers run on the host's\n * server fiber, writing queued messages and alarms to the conversation feed) and used by {@link HarnessService}\n * Tier B to dispatch over the discovered host's `Handle.rpc` — keeping both ends on one contract.\n */\nexport const HarnessControl = RpcGroup.make(\n Rpc.make('setAlarm', {\n payload: Schema.Struct({ at: Schema.DateTimeUtc, message: Schema.NullOr(Schema.String) }),\n success: Schema.Void,\n }),\n Rpc.make('enqueueMessage', {\n payload: Schema.Struct({ content: Schema.Array(ContentBlock.Any) }),\n success: Schema.Void,\n }),\n);\n\n/** Union of the RPCs declared in {@link HarnessControl}. */\nexport type HarnessControlRpcs = RpcGroup.Rpcs<typeof HarnessControl>;\n","//\n// Copyright 2025 DXOS.org\n//\n\nimport defaultsDeep from 'lodash.defaultsdeep';\n\nimport { Model } from '@dxos/ai';\nimport * as Template from '@dxos/compute/Template';\n// Text is referenced in the inferred type of 'templates' (via Template.make → Template.Template.source → Ref.Ref(Text.Text));\n// the import lets TypeScript name it in the emitted .d.ts.\n// eslint-disable-next-line unused-imports/no-unused-imports\nimport { type Text } from '@dxos/schema';\n\nimport FORMAT from './instructions/format.tpl?raw';\nimport SYSTEM from './instructions/system.tpl?raw';\n\n/**\n * System template variables.\n */\nexport type SystemPromptOptions = Model.Capabilities & {\n DATETIME: string;\n};\n\n/**\n * Base system prompt.\n * NOTE: This contains protocol instructions that can not be dynamically edited.\n */\nexport const createSystemPrompt = (options: Partial<SystemPromptOptions> = {}) =>\n Template.process<SystemPromptOptions>(\n FORMAT,\n defaultsDeep(options, {\n DATETIME: new Date().toISOString(),\n }),\n );\n\n/**\n * NOTE: We are forbidden from accessing randomness at model level in cloudflare, so we have to have pre-generated ids.\n */\nconst SYSTEM_ID = '01K2J2FZWH39F55CS7B26GP1Q3';\n\nexport const templates = {\n system: Template.make({\n id: SYSTEM_ID,\n source: SYSTEM,\n }),\n};\n"],"mappings":"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"}
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { Request };
|
|
1
|
+
export { n as Request } from "../chunk-AiRequest.mjs";
|
|
@@ -1,462 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import * as Context from "effect/Context";
|
|
3
|
-
import * as Effect from "effect/Effect";
|
|
4
|
-
import * as Schema from "effect/Schema";
|
|
5
|
-
import { DXN, Database, Feed, Obj, Query, Ref, Type } from "@dxos/echo";
|
|
6
|
-
import { assertArgument, invariant } from "@dxos/invariant";
|
|
7
|
-
import { log } from "@dxos/log";
|
|
8
|
-
import { EID as EID$1 } from "@dxos/keys";
|
|
9
|
-
import { ComplexSet, isNonNullable } from "@dxos/util";
|
|
10
|
-
import * as Function from "effect/Function";
|
|
11
|
-
import * as EArray from "effect/Array";
|
|
12
|
-
import * as Order from "effect/Order";
|
|
13
|
-
import * as Atom from "effect/reactivity/Atom";
|
|
14
|
-
import * as Skill from "@dxos/compute/Skill";
|
|
15
|
-
import { Resource } from "@dxos/context";
|
|
16
|
-
import * as AtomEx from "@dxos/effect/AtomEx";
|
|
17
|
-
import * as RuntimeProvider from "@dxos/effect/RuntimeProvider";
|
|
18
|
-
//#region src/session/AiContext.ts
|
|
19
|
-
var AiContext_exports = /* @__PURE__ */ __exportAll({
|
|
20
|
-
Binder: () => Binder,
|
|
21
|
-
Binding: () => Binding,
|
|
22
|
-
Bindings: () => Bindings
|
|
23
|
-
});
|
|
24
|
-
var __dxlog_file = "/__w/dxos/dxos/packages/core/compute/assistant/src/session/AiContext.ts";
|
|
25
|
-
/**
|
|
26
|
-
* Thread message that binds or unbinds contextual objects to a conversation.
|
|
27
|
-
*/
|
|
28
|
-
var Binding = class extends Type.makeObject(DXN.make("org.dxos.type.contextBinding", "0.1.0"))(Schema.Struct({
|
|
29
|
-
skills: Schema.Struct({
|
|
30
|
-
added: Schema.Array(Ref.Ref(Skill.Skill)),
|
|
31
|
-
removed: Schema.Array(Ref.Ref(Skill.Skill))
|
|
32
|
-
}),
|
|
33
|
-
objects: Schema.Struct({
|
|
34
|
-
added: Schema.Array(Ref.Ref(Obj.Unknown)),
|
|
35
|
-
removed: Schema.Array(Ref.Ref(Obj.Unknown))
|
|
36
|
-
})
|
|
37
|
-
})) {};
|
|
38
|
-
var Bindings = class {
|
|
39
|
-
skills = new ComplexSet((ref) => ref.uri);
|
|
40
|
-
objects = new ComplexSet((ref) => {
|
|
41
|
-
const echoUri = EID$1.tryParse(ref.uri);
|
|
42
|
-
return echoUri ? EID$1.getEntityId(echoUri) : void 0;
|
|
43
|
-
});
|
|
44
|
-
toJSON() {
|
|
45
|
-
return {
|
|
46
|
-
skills: EArray.fromIterable(this.skills).map((ref) => ref.uri),
|
|
47
|
-
objects: EArray.fromIterable(this.objects).map((ref) => ref.uri)
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* Bindings appended in this realm, per feed id (stable whether or not the feed is persisted yet).
|
|
53
|
-
*
|
|
54
|
-
* Lets {@link Binder.sync} skip its re-read when nothing here could have changed the bindings: the
|
|
55
|
-
* re-read is a feed-scoped query, which waits for an index pass over every pending write, and it
|
|
56
|
-
* exists only for read-your-writes — a binding written elsewhere arrives through the live query.
|
|
57
|
-
*/
|
|
58
|
-
var bindingWrites = /* @__PURE__ */ new Map();
|
|
59
|
-
var bindingWriteCount = (feed) => bindingWrites.get(feed.id) ?? 0;
|
|
60
|
-
var countBindingWrite = (feed) => {
|
|
61
|
-
bindingWrites.set(feed.id, (bindingWrites.get(feed.id) ?? 0) + 1);
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* Manages bindings of skills and objects to a conversation.
|
|
65
|
-
*/
|
|
66
|
-
var Binder = class extends Resource {
|
|
67
|
-
_skills = Atom.make([]).pipe(Atom.keepAlive);
|
|
68
|
-
_objects = Atom.make([]).pipe(Atom.keepAlive);
|
|
69
|
-
_registry;
|
|
70
|
-
_feed;
|
|
71
|
-
_runtime;
|
|
72
|
-
_hold;
|
|
73
|
-
#bindingsQuery;
|
|
74
|
-
/** {@link bindingWriteCount} at the last read of the bindings query. */
|
|
75
|
-
#readWrites = 0;
|
|
76
|
-
/**
|
|
77
|
-
* Keys of the refs the feed already binds, whether or not their targets resolve here: a registry
|
|
78
|
-
* skill bound by URI never matches its resolved target's URI, so the atoms alone cannot tell it is bound.
|
|
79
|
-
*/
|
|
80
|
-
#bound = {
|
|
81
|
-
skills: /* @__PURE__ */ new Set(),
|
|
82
|
-
objects: /* @__PURE__ */ new Set()
|
|
83
|
-
};
|
|
84
|
-
#pending;
|
|
85
|
-
/** Bumped by each held write, so only the latest resolution of the held bindings lands. */
|
|
86
|
-
#heldGeneration = 0;
|
|
87
|
-
constructor(options) {
|
|
88
|
-
super();
|
|
89
|
-
assertArgument(options.feed, "options.feed", "Feed is required");
|
|
90
|
-
assertArgument(options.runtime, "options.runtime", "Feed runtime is required");
|
|
91
|
-
this._feed = options.feed;
|
|
92
|
-
this._runtime = options.runtime;
|
|
93
|
-
this._registry = options.registry ?? AtomEx.makeRegistry();
|
|
94
|
-
this._hold = options.hold ?? false;
|
|
95
|
-
}
|
|
96
|
-
/**
|
|
97
|
-
* Returns the skills atom for subscription.
|
|
98
|
-
*/
|
|
99
|
-
get skills() {
|
|
100
|
-
return this._skills;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Returns the objects atom for subscription.
|
|
104
|
-
*/
|
|
105
|
-
get objects() {
|
|
106
|
-
return this._objects;
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* Gets the current skills value.
|
|
110
|
-
*/
|
|
111
|
-
getSkills() {
|
|
112
|
-
return this._registry.get(this._skills);
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Gets the current objects value.
|
|
116
|
-
*/
|
|
117
|
-
getObjects() {
|
|
118
|
-
return this._registry.get(this._objects);
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Subscribe to changes in skills.
|
|
122
|
-
*/
|
|
123
|
-
subscribeSkills(cb) {
|
|
124
|
-
return this._registry.subscribe(this._skills, () => cb(this._registry.get(this._skills)));
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Subscribe to changes in objects.
|
|
128
|
-
*/
|
|
129
|
-
subscribeObjects(cb) {
|
|
130
|
-
return this._registry.subscribe(this._objects, () => cb(this._registry.get(this._objects)));
|
|
131
|
-
}
|
|
132
|
-
async _open() {
|
|
133
|
-
if (this._hold) {
|
|
134
|
-
this.#pending = [];
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
await this._follow();
|
|
138
|
-
}
|
|
139
|
-
/**
|
|
140
|
-
* Writes a holding binder's bindings to its feed, which the caller has stored, as one binding. Later
|
|
141
|
-
* writes go straight to the feed, which the binder does not follow.
|
|
142
|
-
*/
|
|
143
|
-
async flush() {
|
|
144
|
-
const held = this.#pending;
|
|
145
|
-
if (!held) return;
|
|
146
|
-
invariant(Obj.getDatabase(this._feed), "The feed must be stored before its bindings are flushed.", {
|
|
147
|
-
"~LogMeta": "~LogMeta",
|
|
148
|
-
F: __dxlog_file,
|
|
149
|
-
L: 184,
|
|
150
|
-
S: this,
|
|
151
|
-
A: ["Obj.getDatabase(this._feed)", "'The feed must be stored before its bindings are flushed.'"]
|
|
152
|
-
});
|
|
153
|
-
this.#pending = void 0;
|
|
154
|
-
const { skills, objects } = this._reduce(held);
|
|
155
|
-
if (skills.size > 0 || objects.size > 0) await this._append(Obj.make(Binding, {
|
|
156
|
-
skills: {
|
|
157
|
-
added: [...skills],
|
|
158
|
-
removed: []
|
|
159
|
-
},
|
|
160
|
-
objects: {
|
|
161
|
-
added: [...objects],
|
|
162
|
-
removed: []
|
|
163
|
-
}
|
|
164
|
-
}));
|
|
165
|
-
}
|
|
166
|
-
async _follow() {
|
|
167
|
-
const bindingsQuery = await RuntimeProvider.runPromise(Effect.succeed(this._runtime))(Feed.query(this._feed, Query.type(Binding)));
|
|
168
|
-
this.#bindingsQuery = bindingsQuery;
|
|
169
|
-
this.#readWrites = bindingWriteCount(this._feed);
|
|
170
|
-
const initialResults = await bindingsQuery.run();
|
|
171
|
-
await this._updateBindings(initialResults);
|
|
172
|
-
this._ctx.onDispose(bindingsQuery.subscribe(async () => {
|
|
173
|
-
await this._updateBindings(bindingsQuery.results);
|
|
174
|
-
}));
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Re-reads bindings from the feed to pick up changes made by other processes in this realm, such
|
|
178
|
-
* as a tool that bound a skill. A no-op when none has been written since the last read.
|
|
179
|
-
*/
|
|
180
|
-
async sync() {
|
|
181
|
-
const writes = bindingWriteCount(this._feed);
|
|
182
|
-
if (this.#bindingsQuery && writes !== this.#readWrites) {
|
|
183
|
-
let results;
|
|
184
|
-
try {
|
|
185
|
-
results = await this.#bindingsQuery.run();
|
|
186
|
-
} catch (error) {
|
|
187
|
-
log.warn("bindings sync failed; keeping the current bindings", { error }, {
|
|
188
|
-
"~LogMeta": "~LogMeta",
|
|
189
|
-
F: __dxlog_file,
|
|
190
|
-
L: 230,
|
|
191
|
-
S: this
|
|
192
|
-
});
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
log("sync", { bindingItems: results.length }, {
|
|
196
|
-
"~LogMeta": "~LogMeta",
|
|
197
|
-
F: __dxlog_file,
|
|
198
|
-
L: 233,
|
|
199
|
-
S: this
|
|
200
|
-
});
|
|
201
|
-
await this._updateBindings(results);
|
|
202
|
-
this.#readWrites = writes;
|
|
203
|
-
log("sync complete", {
|
|
204
|
-
skills: this._registry.get(this._skills).length,
|
|
205
|
-
skillKeys: this._registry.get(this._skills).map((skill) => Obj.getMeta(skill).key)
|
|
206
|
-
}, {
|
|
207
|
-
"~LogMeta": "~LogMeta",
|
|
208
|
-
F: __dxlog_file,
|
|
209
|
-
L: 237,
|
|
210
|
-
S: this
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
async _updateBindings(items) {
|
|
215
|
-
if (items.length === 0) return;
|
|
216
|
-
const bindings = this._reduce(inAppendOrder(items));
|
|
217
|
-
this.#bound = {
|
|
218
|
-
skills: new Set([...bindings.skills].map((ref) => refKey(ref.uri))),
|
|
219
|
-
objects: new Set([...bindings.objects].map((ref) => refKey(ref.uri)))
|
|
220
|
-
};
|
|
221
|
-
log("_updateBindings", {
|
|
222
|
-
items: items.length,
|
|
223
|
-
skillRefs: [...bindings.skills].map((ref) => ({
|
|
224
|
-
uri: ref.uri,
|
|
225
|
-
available: ref.isAvailable
|
|
226
|
-
}))
|
|
227
|
-
}, {
|
|
228
|
-
"~LogMeta": "~LogMeta",
|
|
229
|
-
F: __dxlog_file,
|
|
230
|
-
L: 258,
|
|
231
|
-
S: this
|
|
232
|
-
});
|
|
233
|
-
const currentSkills = this._registry.get(this._skills);
|
|
234
|
-
const currentObjects = this._registry.get(this._objects);
|
|
235
|
-
const resolvedSkills = await this._resolve(bindings.skills, currentSkills);
|
|
236
|
-
const resolvedObjects = await this._resolve(bindings.objects, currentObjects);
|
|
237
|
-
log("_updateBindings resolved", {
|
|
238
|
-
resolvedSkills: resolvedSkills.length,
|
|
239
|
-
resolvedSkillKeys: resolvedSkills.map((bp) => Obj.getMeta(bp).key ?? "<missing>")
|
|
240
|
-
}, {
|
|
241
|
-
"~LogMeta": "~LogMeta",
|
|
242
|
-
F: __dxlog_file,
|
|
243
|
-
L: 269,
|
|
244
|
-
S: this
|
|
245
|
-
});
|
|
246
|
-
const reducedSkillDxns = new Set([...bindings.skills].map((ref) => ref.uri));
|
|
247
|
-
const reducedObjectDxns = new Set([...bindings.objects].map((ref) => ref.uri));
|
|
248
|
-
const filteredSkills = currentSkills.filter((obj) => {
|
|
249
|
-
const uri = Obj.getURI(obj);
|
|
250
|
-
return uri != null && reducedSkillDxns.has(uri);
|
|
251
|
-
});
|
|
252
|
-
const filteredObjects = currentObjects.filter((obj) => {
|
|
253
|
-
const uri = Obj.getURI(obj);
|
|
254
|
-
return uri != null && reducedObjectDxns.has(uri);
|
|
255
|
-
});
|
|
256
|
-
const mergedSkills = this._mergeInto(filteredSkills, resolvedSkills);
|
|
257
|
-
const mergedObjects = this._mergeInto(filteredObjects, resolvedObjects);
|
|
258
|
-
this._registry.set(this._skills, mergedSkills);
|
|
259
|
-
this._registry.set(this._objects, mergedObjects);
|
|
260
|
-
log("updated bindings", {
|
|
261
|
-
skills: mergedSkills.length,
|
|
262
|
-
objects: mergedObjects.length
|
|
263
|
-
}, {
|
|
264
|
-
"~LogMeta": "~LogMeta",
|
|
265
|
-
F: __dxlog_file,
|
|
266
|
-
L: 292,
|
|
267
|
-
S: this
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
async _close() {
|
|
271
|
-
this._registry.set(this._skills, []);
|
|
272
|
-
this._registry.set(this._objects, []);
|
|
273
|
-
}
|
|
274
|
-
async bind({ skills, objects }) {
|
|
275
|
-
const currentSkills = this._registry.get(this._skills);
|
|
276
|
-
const currentObjects = this._registry.get(this._objects);
|
|
277
|
-
const { added: addedSkills, next: nextSkills } = this._processBindings(skills, currentSkills, this.#bound.skills);
|
|
278
|
-
const { added: addedObjects, next: nextObjects } = this._processBindings(objects, currentObjects, this.#bound.objects);
|
|
279
|
-
if (!addedSkills.length && !addedObjects.length) return;
|
|
280
|
-
addedSkills.forEach((ref) => this.#bound.skills.add(refKey(ref.uri)));
|
|
281
|
-
addedObjects.forEach((ref) => this.#bound.objects.add(refKey(ref.uri)));
|
|
282
|
-
this._registry.set(this._skills, nextSkills);
|
|
283
|
-
this._registry.set(this._objects, nextObjects);
|
|
284
|
-
log("bind", {
|
|
285
|
-
skills: addedSkills.length,
|
|
286
|
-
objects: addedObjects.length
|
|
287
|
-
}, {
|
|
288
|
-
"~LogMeta": "~LogMeta",
|
|
289
|
-
F: __dxlog_file,
|
|
290
|
-
L: 324,
|
|
291
|
-
S: this
|
|
292
|
-
});
|
|
293
|
-
await this._write(Obj.make(Binding, {
|
|
294
|
-
skills: {
|
|
295
|
-
added: addedSkills,
|
|
296
|
-
removed: []
|
|
297
|
-
},
|
|
298
|
-
objects: {
|
|
299
|
-
added: addedObjects,
|
|
300
|
-
removed: []
|
|
301
|
-
}
|
|
302
|
-
}));
|
|
303
|
-
}
|
|
304
|
-
async unbind({ skills, objects }) {
|
|
305
|
-
if (!skills?.length && !objects?.length) return;
|
|
306
|
-
(skills ?? []).forEach((ref) => this.#bound.skills.delete(refKey(ref.uri)));
|
|
307
|
-
(objects ?? []).forEach((ref) => this.#bound.objects.delete(refKey(ref.uri)));
|
|
308
|
-
const removedSkillKeys = new Set((skills ?? []).map((ref) => refKey(ref.uri)));
|
|
309
|
-
const removedObjectKeys = new Set((objects ?? []).map((ref) => refKey(ref.uri)));
|
|
310
|
-
if (removedSkillKeys.size > 0) {
|
|
311
|
-
const current = this._registry.get(this._skills);
|
|
312
|
-
this._registry.set(this._skills, current.filter((obj) => !removedSkillKeys.has(refKey(Obj.getURI(obj)))));
|
|
313
|
-
}
|
|
314
|
-
if (removedObjectKeys.size > 0) {
|
|
315
|
-
const current = this._registry.get(this._objects);
|
|
316
|
-
this._registry.set(this._objects, current.filter((obj) => !removedObjectKeys.has(refKey(Obj.getURI(obj)))));
|
|
317
|
-
}
|
|
318
|
-
log("unbind", {
|
|
319
|
-
skills: skills?.length,
|
|
320
|
-
objects: objects?.length
|
|
321
|
-
}, {
|
|
322
|
-
"~LogMeta": "~LogMeta",
|
|
323
|
-
F: __dxlog_file,
|
|
324
|
-
L: 365,
|
|
325
|
-
S: this
|
|
326
|
-
});
|
|
327
|
-
await this._write(Obj.make(Binding, {
|
|
328
|
-
skills: {
|
|
329
|
-
added: [],
|
|
330
|
-
removed: skills ?? []
|
|
331
|
-
},
|
|
332
|
-
objects: {
|
|
333
|
-
added: [],
|
|
334
|
-
removed: objects ?? []
|
|
335
|
-
}
|
|
336
|
-
}));
|
|
337
|
-
}
|
|
338
|
-
async _write(binding) {
|
|
339
|
-
if (this.#pending) {
|
|
340
|
-
this.#pending.push(binding);
|
|
341
|
-
await this._resolveHeld(this.#pending);
|
|
342
|
-
return;
|
|
343
|
-
}
|
|
344
|
-
await this._append(binding);
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* Sets the atoms from the held bindings. Their refs have no feed query to hydrate them, so each is
|
|
348
|
-
* resolved against the database, which also spans the registry.
|
|
349
|
-
*/
|
|
350
|
-
async _resolveHeld(held) {
|
|
351
|
-
const generation = ++this.#heldGeneration;
|
|
352
|
-
const { db } = Context.get(this._runtime, Database.Service);
|
|
353
|
-
const { skills, objects } = this._reduce(held);
|
|
354
|
-
const hydrate = (refs) => [...refs].map((ref) => ref.isAvailable ? ref : db.makeRef(ref.uri));
|
|
355
|
-
const [resolvedSkills, resolvedObjects] = await Promise.all([this._resolve(hydrate(skills), this._registry.get(this._skills)), this._resolve(hydrate(objects), this._registry.get(this._objects))]);
|
|
356
|
-
if (generation !== this.#heldGeneration) return;
|
|
357
|
-
this._registry.set(this._skills, resolvedSkills);
|
|
358
|
-
this._registry.set(this._objects, resolvedObjects);
|
|
359
|
-
}
|
|
360
|
-
async _append(binding) {
|
|
361
|
-
await RuntimeProvider.runPromise(Effect.succeed(this._runtime))(Feed.append(this._feed, [binding]));
|
|
362
|
-
countBindingWrite(this._feed);
|
|
363
|
-
}
|
|
364
|
-
/**
|
|
365
|
-
* Process bindings to filter duplicates (against the resolved targets and the refs already bound) and
|
|
366
|
-
* determine next state.
|
|
367
|
-
*/
|
|
368
|
-
_processBindings(refs, current, bound) {
|
|
369
|
-
const next = [...current];
|
|
370
|
-
const added = [];
|
|
371
|
-
if (!refs?.length) return {
|
|
372
|
-
added,
|
|
373
|
-
next
|
|
374
|
-
};
|
|
375
|
-
const seen = /* @__PURE__ */ new Set([...bound, ...current.map((obj) => refKey(Obj.getURI(obj)))]);
|
|
376
|
-
for (const ref of refs) {
|
|
377
|
-
const key = refKey(ref.uri);
|
|
378
|
-
if (seen.has(key)) continue;
|
|
379
|
-
seen.add(key);
|
|
380
|
-
added.push(ref);
|
|
381
|
-
if (ref.isAvailable) {
|
|
382
|
-
const target = ref.target;
|
|
383
|
-
if (target) next.push(target);
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
return {
|
|
387
|
-
added,
|
|
388
|
-
next
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
/**
|
|
392
|
-
* Reduce results into sets of skills and objects.
|
|
393
|
-
*
|
|
394
|
-
* Order-sensitive: a later removal must fold after the addition it undoes, so callers pass items
|
|
395
|
-
* in append order (see {@link inAppendOrder}).
|
|
396
|
-
*/
|
|
397
|
-
_reduce(items) {
|
|
398
|
-
return Function.pipe(items, EArray.reduce(new Bindings(), (context, { skills, objects }) => {
|
|
399
|
-
skills.added.forEach((ref) => context.skills.add(ref));
|
|
400
|
-
skills.removed.forEach((ref) => context.skills.delete(ref));
|
|
401
|
-
objects.added.forEach((ref) => context.objects.add(ref));
|
|
402
|
-
objects.removed.forEach((ref) => {
|
|
403
|
-
for (const obj of context.objects) if (obj.uri === ref.uri || EID$1.tryParse(obj.uri) && EID$1.tryParse(ref.uri) && EID$1.getEntityId(EID$1.tryParse(obj.uri)) === EID$1.getEntityId(EID$1.tryParse(ref.uri))) context.objects.delete(obj);
|
|
404
|
-
});
|
|
405
|
-
return context;
|
|
406
|
-
}));
|
|
407
|
-
}
|
|
408
|
-
/**
|
|
409
|
-
* Merge resolved items into the current set, adding only items not already present (by DXN).
|
|
410
|
-
*/
|
|
411
|
-
_mergeInto(current, resolved) {
|
|
412
|
-
const seen = new Set(current.map((obj) => Obj.getURI(obj)));
|
|
413
|
-
const merged = [...current];
|
|
414
|
-
for (const obj of resolved) {
|
|
415
|
-
const uri = Obj.getURI(obj);
|
|
416
|
-
if (!seen.has(uri)) {
|
|
417
|
-
seen.add(uri);
|
|
418
|
-
merged.push(obj);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
return merged;
|
|
422
|
-
}
|
|
423
|
-
/**
|
|
424
|
-
* Resolve references to objects, loading them first if needed and falling back to existing objects.
|
|
425
|
-
* DXN refs (e.g. `dxn:org.dxos.skill.database`) resolve via the wired-up ECHO ref resolver
|
|
426
|
-
* which already spans both the space DB and the hypergraph registry.
|
|
427
|
-
*/
|
|
428
|
-
async _resolve(refs, current) {
|
|
429
|
-
const refArray = [...refs];
|
|
430
|
-
await Promise.all(refArray.map((ref) => ref.tryLoad()));
|
|
431
|
-
return refArray.map((ref) => {
|
|
432
|
-
let target;
|
|
433
|
-
if (ref.isAvailable) target = ref.target;
|
|
434
|
-
const resolved = target ?? current.find((obj) => Obj.getURI(obj) === ref.uri);
|
|
435
|
-
if (!resolved) log.warn("unresolved context binding", { uri: ref.uri }, {
|
|
436
|
-
"~LogMeta": "~LogMeta",
|
|
437
|
-
F: __dxlog_file,
|
|
438
|
-
L: 523,
|
|
439
|
-
S: this
|
|
440
|
-
});
|
|
441
|
-
return resolved;
|
|
442
|
-
}).filter(isNonNullable);
|
|
443
|
-
}
|
|
444
|
-
};
|
|
445
|
-
/**
|
|
446
|
-
* Identity of a bound ref: an ECHO URI compares in its local form, since some carry the space and some do not.
|
|
447
|
-
*/
|
|
448
|
-
var refKey = (uri) => {
|
|
449
|
-
const echoUri = EID$1.tryParse(uri);
|
|
450
|
-
return echoUri ? EID$1.toLocal(echoUri) : uri;
|
|
451
|
-
};
|
|
452
|
-
/**
|
|
453
|
-
* Bindings in the order they were appended, which is the order the fold has to see them: a query
|
|
454
|
-
* returns an unordered set, so an unsorted fold can apply a removal before the addition it undoes
|
|
455
|
-
* and silently keep the object bound. Server-assigned position is authoritative; a locally-written
|
|
456
|
-
* block has none yet and sorts last, which is correct — it is the newest.
|
|
457
|
-
*/
|
|
458
|
-
var inAppendOrder = (items) => EArray.sort(items, Order.mapInput(Order.Number, Feed.getPosition));
|
|
459
|
-
//#endregion
|
|
460
|
-
export { Binder, Binding, Bindings, AiContext_exports as t };
|
|
461
|
-
|
|
462
|
-
//# sourceMappingURL=AiContext.mjs.map
|
|
1
|
+
export { n as Binder, r as Binding, i as Bindings } from "../chunk-AiContext.mjs";
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { Session, serializeMessage, serializePrompt, sessionAnnotations };
|
|
1
|
+
export { n as Session, r as serializeMessage, i as serializePrompt, a as sessionAnnotations } from "../chunk-AiSession.mjs";
|
|
@@ -1,37 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import * as Schema from "effect/Schema";
|
|
3
|
-
import { DXN, Obj, Type } from "@dxos/echo";
|
|
4
|
-
//#region src/session/Alarm.ts
|
|
5
|
-
var Alarm_exports = /* @__PURE__ */ __exportAll({
|
|
6
|
-
Alarm: () => Alarm,
|
|
7
|
-
MAX_SELF_WAKES: () => 10,
|
|
8
|
-
make: () => make
|
|
9
|
-
});
|
|
10
|
-
/**
|
|
11
|
-
* Feed-level record scheduling a future self-wake of the agent.
|
|
12
|
-
* Managed with regular feed CRUD: append schedules, `Feed.remove` cancels a pending alarm. When it
|
|
13
|
-
* fires, the agent appends the wake-up `Message` carrying `SessionStore.AckAnnotation` naming this
|
|
14
|
-
* record — the ack filters it out of the pending set; the record itself stays in the feed.
|
|
15
|
-
*/
|
|
16
|
-
var Alarm = class extends Type.makeObject(DXN.make("org.dxos.type.alarm", "0.1.0"))(Schema.Struct({
|
|
17
|
-
/** Epoch milliseconds at which the agent should wake. */
|
|
18
|
-
wakeAt: Schema.Number,
|
|
19
|
-
/** Reminder surfaced to the agent when the alarm fires. */
|
|
20
|
-
message: Schema.optional(Schema.String),
|
|
21
|
-
/** ISO timestamp when the alarm was scheduled. */
|
|
22
|
-
created: Schema.String
|
|
23
|
-
})) {};
|
|
24
|
-
/**
|
|
25
|
-
* Most alarms that may wake the agent in a row without a user prompt between them; each wake is a full turn over the
|
|
26
|
-
* whole context, so an agent polling on alarms would otherwise spend without bound.
|
|
27
|
-
*/
|
|
28
|
-
var MAX_SELF_WAKES = 10;
|
|
29
|
-
var make = ({ wakeAt, message, created }) => Obj.make(Alarm, {
|
|
30
|
-
wakeAt,
|
|
31
|
-
message,
|
|
32
|
-
created: created ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
33
|
-
});
|
|
34
|
-
//#endregion
|
|
35
|
-
export { Alarm, MAX_SELF_WAKES, make, Alarm_exports as t };
|
|
36
|
-
|
|
37
|
-
//# sourceMappingURL=Alarm.mjs.map
|
|
1
|
+
export { t as Alarm, r as MAX_SELF_WAKES, i as make } from "../chunk-Alarm.mjs";
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
|
|
2
|
-
export { HarnessService, NotSupportedError, bindContext, binder, enqueueMessage, fromBinder, getChat, history, layerSpec, make, queryContext, setAlarm };
|
|
1
|
+
export { t as HarnessService, r as NotSupportedError, i as bindContext, a as binder, o as enqueueMessage, s as fromBinder, c as getChat, l as history, u as layerSpec, d as make, f as queryContext, p as setAlarm } from "../chunk-Harness.mjs";
|
|
@@ -1,20 +1 @@
|
|
|
1
|
-
|
|
2
|
-
import * as Schema from "effect/Schema";
|
|
3
|
-
import { DXN, Feed, Obj, Ref, Type } from "@dxos/echo";
|
|
4
|
-
//#region src/session/SessionLink.ts
|
|
5
|
-
var SessionLink_exports = /* @__PURE__ */ __exportAll({ SessionLink: () => SessionLink });
|
|
6
|
-
/**
|
|
7
|
-
* Feed-level record that links this session to a point in another session's history.
|
|
8
|
-
* When present in a feed, the messages from the referenced feed up to and including
|
|
9
|
-
* `messageId` are prepended to the conversation history before each turn.
|
|
10
|
-
*/
|
|
11
|
-
var SessionLink = class extends Type.makeObject(DXN.make("org.dxos.type.sessionLink", "0.1.0"))(Schema.Struct({
|
|
12
|
-
/** Reference to the feed of the source session. */
|
|
13
|
-
feedRef: Ref.Ref(Feed.Feed),
|
|
14
|
-
/** Messages from the source feed up to and including this message ID are injected. */
|
|
15
|
-
messageId: Obj.ID
|
|
16
|
-
})) {};
|
|
17
|
-
//#endregion
|
|
18
|
-
export { SessionLink, SessionLink_exports as t };
|
|
19
|
-
|
|
20
|
-
//# sourceMappingURL=SessionLink.mjs.map
|
|
1
|
+
export { t as SessionLink } from "../chunk-SessionLink.mjs";
|