@things-factory/ai-assistant 10.1.212 → 10.1.214

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.
Files changed (127) hide show
  1. package/client/components/assistant-chat.ts +115 -2
  2. package/client/components/assistant-dock.ts +106 -3
  3. package/client/components/assistant-selection-bar.test.ts +42 -0
  4. package/client/components/assistant-selection-bar.ts +129 -0
  5. package/client/components/workspace-view.ts +56 -3
  6. package/client/index.ts +5 -0
  7. package/client/utils/assistant-ask.test.ts +38 -0
  8. package/client/utils/assistant-ask.ts +35 -1
  9. package/client/utils/assistant-proposals.ts +23 -0
  10. package/client/utils/assistant-selection.test.ts +54 -0
  11. package/client/utils/assistant-selection.ts +74 -0
  12. package/client/utils/assistant-session-controller.ts +2 -0
  13. package/client/utils/assistant-session-transport.ts +1 -1
  14. package/client/utils/invite-proposal-register.ts +31 -0
  15. package/client/utils/invite-proposal.test.ts +40 -0
  16. package/client/utils/invite-proposal.ts +54 -0
  17. package/dist-client/components/assistant-chat.d.ts +18 -0
  18. package/dist-client/components/assistant-chat.js +117 -2
  19. package/dist-client/components/assistant-chat.js.map +1 -1
  20. package/dist-client/components/assistant-dock.d.ts +11 -0
  21. package/dist-client/components/assistant-dock.js +97 -4
  22. package/dist-client/components/assistant-dock.js.map +1 -1
  23. package/dist-client/components/assistant-selection-bar.d.ts +44 -0
  24. package/dist-client/components/assistant-selection-bar.js +149 -0
  25. package/dist-client/components/assistant-selection-bar.js.map +1 -0
  26. package/dist-client/components/assistant-selection-bar.test.d.ts +1 -0
  27. package/dist-client/components/assistant-selection-bar.test.js +38 -0
  28. package/dist-client/components/assistant-selection-bar.test.js.map +1 -0
  29. package/dist-client/components/workspace-view.d.ts +2 -0
  30. package/dist-client/components/workspace-view.js +58 -3
  31. package/dist-client/components/workspace-view.js.map +1 -1
  32. package/dist-client/index.d.ts +3 -0
  33. package/dist-client/index.js +5 -0
  34. package/dist-client/index.js.map +1 -1
  35. package/dist-client/tsconfig.tsbuildinfo +1 -1
  36. package/dist-client/utils/assistant-ask.d.ts +22 -1
  37. package/dist-client/utils/assistant-ask.js +19 -0
  38. package/dist-client/utils/assistant-ask.js.map +1 -1
  39. package/dist-client/utils/assistant-ask.test.d.ts +1 -0
  40. package/dist-client/utils/assistant-ask.test.js +40 -0
  41. package/dist-client/utils/assistant-ask.test.js.map +1 -0
  42. package/dist-client/utils/assistant-proposals.d.ts +14 -0
  43. package/dist-client/utils/assistant-proposals.js +7 -0
  44. package/dist-client/utils/assistant-proposals.js.map +1 -1
  45. package/dist-client/utils/assistant-selection.d.ts +43 -0
  46. package/dist-client/utils/assistant-selection.js +59 -0
  47. package/dist-client/utils/assistant-selection.js.map +1 -0
  48. package/dist-client/utils/assistant-selection.test.d.ts +1 -0
  49. package/dist-client/utils/assistant-selection.test.js +46 -0
  50. package/dist-client/utils/assistant-selection.test.js.map +1 -0
  51. package/dist-client/utils/assistant-session-controller.d.ts +2 -0
  52. package/dist-client/utils/assistant-session-controller.js.map +1 -1
  53. package/dist-client/utils/assistant-session-transport.js +1 -1
  54. package/dist-client/utils/assistant-session-transport.js.map +1 -1
  55. package/dist-client/utils/invite-proposal-register.d.ts +1 -0
  56. package/dist-client/utils/invite-proposal-register.js +24 -0
  57. package/dist-client/utils/invite-proposal-register.js.map +1 -0
  58. package/dist-client/utils/invite-proposal.d.ts +17 -0
  59. package/dist-client/utils/invite-proposal.js +37 -0
  60. package/dist-client/utils/invite-proposal.js.map +1 -0
  61. package/dist-client/utils/invite-proposal.test.d.ts +1 -0
  62. package/dist-client/utils/invite-proposal.test.js +35 -0
  63. package/dist-client/utils/invite-proposal.test.js.map +1 -0
  64. package/dist-server/service/assistant-chat-resolver.js +7 -3
  65. package/dist-server/service/assistant-chat-resolver.js.map +1 -1
  66. package/dist-server/service/assistant-mode/index.d.ts +2 -1
  67. package/dist-server/service/assistant-mode/index.js +6 -1
  68. package/dist-server/service/assistant-mode/index.js.map +1 -1
  69. package/dist-server/service/assistant-mode/mode-categories.d.ts +29 -1
  70. package/dist-server/service/assistant-mode/mode-categories.js +57 -5
  71. package/dist-server/service/assistant-mode/mode-categories.js.map +1 -1
  72. package/dist-server/service/assistant-mode/screen-rules.d.ts +6 -0
  73. package/dist-server/service/assistant-mode/screen-rules.js +21 -6
  74. package/dist-server/service/assistant-mode/screen-rules.js.map +1 -1
  75. package/dist-server/service/data-read/read-target.d.ts +24 -3
  76. package/dist-server/service/data-read/read-target.js +42 -10
  77. package/dist-server/service/data-read/read-target.js.map +1 -1
  78. package/dist-server/service/data-read/read-tools.d.ts +18 -1
  79. package/dist-server/service/data-read/read-tools.js +19 -5
  80. package/dist-server/service/data-read/read-tools.js.map +1 -1
  81. package/dist-server/service/index.d.ts +5 -1
  82. package/dist-server/service/index.js +10 -1
  83. package/dist-server/service/index.js.map +1 -1
  84. package/dist-server/service/people/index.d.ts +4 -0
  85. package/dist-server/service/people/index.js +22 -0
  86. package/dist-server/service/people/index.js.map +1 -0
  87. package/dist-server/service/people/invite-tools.d.ts +34 -0
  88. package/dist-server/service/people/invite-tools.js +144 -0
  89. package/dist-server/service/people/invite-tools.js.map +1 -0
  90. package/dist-server/service/people/people-keys.d.ts +8 -0
  91. package/dist-server/service/people/people-keys.js +16 -0
  92. package/dist-server/service/people/people-keys.js.map +1 -0
  93. package/dist-server/service/people/people-read.d.ts +4 -0
  94. package/dist-server/service/people/people-read.js +57 -0
  95. package/dist-server/service/people/people-read.js.map +1 -0
  96. package/dist-server/service/testing/mode-conformance.js +3 -0
  97. package/dist-server/service/testing/mode-conformance.js.map +1 -1
  98. package/dist-server/tsconfig.tsbuildinfo +1 -1
  99. package/package.json +6 -6
  100. package/server/service/assistant-chat-resolver.ts +8 -4
  101. package/server/service/assistant-mode/conversation-category.test.ts +35 -0
  102. package/server/service/assistant-mode/index.ts +3 -1
  103. package/server/service/assistant-mode/mode-categories.ts +72 -5
  104. package/server/service/assistant-mode/mode-front.test.ts +32 -4
  105. package/server/service/assistant-mode/resolve.test.ts +1 -1
  106. package/server/service/assistant-mode/screen-rules.test.ts +23 -1
  107. package/server/service/assistant-mode/screen-rules.ts +22 -5
  108. package/server/service/data-entry/data-entry.test.ts +2 -2
  109. package/server/service/data-read/detail-lists.test.ts +61 -0
  110. package/server/service/data-read/read-target.ts +54 -9
  111. package/server/service/data-read/read-tools.ts +32 -6
  112. package/server/service/index.ts +7 -1
  113. package/server/service/people/index.ts +13 -0
  114. package/server/service/people/invite-tools.ts +159 -0
  115. package/server/service/people/invite.test.ts +159 -0
  116. package/server/service/people/people-keys.ts +16 -0
  117. package/server/service/people/people-read.test.ts +82 -0
  118. package/server/service/people/people-read.ts +56 -0
  119. package/server/service/testing/mode-conformance.test.ts +14 -1
  120. package/server/service/testing/mode-conformance.ts +2 -0
  121. package/test/assistant-dock.test.ts +73 -0
  122. package/translations/en.json +25 -1
  123. package/translations/es.json +25 -1
  124. package/translations/ja.json +25 -1
  125. package/translations/ko.json +25 -1
  126. package/translations/ms.json +25 -1
  127. package/translations/zh.json +25 -1
@@ -1 +1 @@
1
- {"version":3,"file":"read-tools.js","sourceRoot":"","sources":["../../../server/service/data-read/read-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The tools of an AI 조회 target (operato-application/design/ai/read-targets.md §4, §5).\n *\n * query<X> reads the rows through the application's list query as the person, and tells the model the count, the\n * sums, the groups and a few rows. A longer result goes on the AI 작업판 as a proposal the server builds from the rows\n * themselves - the table is never written by the model. open<X>Screen reads nothing: it hands the card the address\n * of the application's list screen with the conditions it takes.\n */\nimport { registerToolCategory, type ToolCategory, type ToolSpec } from '@things-factory/ai-client-base'\n\nimport { readFieldValue, rootFieldOf } from '../data-entry/entry-target.js'\nimport type { GraphqlRunner } from '../data-entry/entry-update.js'\nimport { runAsCaller } from '../data-entry/entry-tools.js'\nimport { normalizeWorkspace, workspaceContents } from '../workspace/workspace-blocks.js'\nimport {\n declareReadTarget,\n filtersOf,\n currenciesOf,\n declareDetailRead,\n detailToolName,\n MAX_DETAIL_CHARS,\n type DetailArg,\n type DetailRead,\n groupsOf,\n queryToolName,\n readCategoryName,\n readCriteria,\n readRows,\n ROWS_FOR_MODEL,\n screenAddress,\n screenToolName,\n sumsOf,\n type ReadCriterion,\n type ReadTarget\n} from './read-target.js'\n\n/** The reader's words for a key - the key's own default when the translator has none. */\nconst wordsOf = (context: any) => (key: string | undefined, fallback: string) => {\n if (!key || typeof context?.t !== 'function') return fallback\n try {\n const said = context.t(key)\n return said && said !== key ? String(said) : fallback\n } catch {\n return fallback\n }\n}\n\nfunction criterionSchema(criterion: ReadCriterion): any {\n /* One type per field - Gemini's function schema refuses a list of types (2026-10-01). */\n const type = criterion.type === 'number' ? 'number' : criterion.type === 'integer' ? 'integer' : criterion.type === 'boolean' ? 'boolean' : 'string'\n const said = [criterion.description, criterion.type === 'date' ? 'YYYY-MM-DD' : undefined, criterion.type === 'enum' ? `one of: ${criterion.values!.join(', ')}` : undefined]\n .filter(Boolean)\n .join('. ')\n return { type, ...(said ? { description: said } : {}) }\n}\n\nexport async function queryRecords(target: ReadTarget, args: any, context: any, run: GraphqlRunner) {\n const { criteria, refused } = readCriteria(target, args)\n if (refused.length) {\n return { rejected: true, error: 'condition-unreadable', refused, message: `these conditions do not fit their type: ${refused.map(one => `${one.name} (${one.code})`).join(', ')}. Fix them and call again.` }\n }\n let read\n try {\n read = await readRows(target, filtersOf(target, criteria), run, typeof criteria.text === 'string' && target.search ? criteria.text : undefined)\n } catch (error: any) {\n return { rejected: true, error: 'query-failed', message: `the list could not be read: ${error?.message ?? error}` }\n }\n const { rows, total, complete } = read\n const sums = sumsOf(target, rows)\n const groupBy = typeof args?.groupBy === 'string' && args.groupBy ? args.groupBy : undefined\n const groups = groupBy ? groupsOf(target, rows, groupBy) : undefined\n const words = wordsOf(context)\n const label = words(target.labelKey, target.key)\n\n const said = {\n target: target.key,\n criteria,\n total,\n read: rows.length,\n complete,\n sums,\n ...(groupBy ? (groups ? { groupBy, groups: groups.slice(0, 50), ...(groups.length > 50 ? { moreGroups: groups.length - 50 } : {}) } : { groupBy, groupRefused: 'no such column' }) : {}),\n rows: rows.slice(0, ROWS_FOR_MODEL),\n ...(rows.length > ROWS_FOR_MODEL ? { rowsNotShown: rows.length - ROWS_FOR_MODEL } : {})\n }\n const incomplete = complete\n ? ''\n : ` Only ${rows.length} of ${total} rows were read; the sums and groups are of those rows, not of the list - say so, and ask the person to narrow the conditions.`\n\n if (rows.length === 1 && args?.show !== 'workspace') {\n return { ...said, record: rows[0], message: 'one record - answer from its fields; say a field it does not have as not recorded.' }\n }\n if (rows.length <= ROWS_FOR_MODEL && args?.show !== 'workspace') {\n return { ...said, message: `${rows.length} rows of ${total}.${incomplete} Answer from these rows; every number you say comes from them.` }\n }\n\n /* The workspace is built here from the rows as read - the model never copies the table. */\n const columns = target.columns.map(column => ({ name: column.name, label: words(column.labelKey, column.name), type: column.type }))\n const totalColumns = target.columns.filter(one => one.total)\n /* A sum per currency is one figure and one group column per currency it holds - 「계약금액 (USD)」. */\n const sumColumns = totalColumns.flatMap(column => {\n const label = words(column.labelKey, column.name)\n const codes = currenciesOf([sums, ...(groups ?? []).map(group => group.sums)], column.name)\n return column.currency\n ? codes.map(code => ({ name: `${column.name}:${code}`, label: `${label} (${code})`, of: (one: Record<string, any>) => one[column.name]?.[code] ?? 0 }))\n : [{ name: column.name, label, of: (one: Record<string, any>) => one[column.name] }]\n })\n const title = typeof args?.title === 'string' && args.title.trim() ? args.title.trim() : `${label} · ${rows.length}`\n const { workspace } = normalizeWorkspace({\n name: typeof args?.name === 'string' && args.name ? args.name : target.key.replace(/\\./g, '-'),\n title,\n ...(complete ? {} : { summary: `${total} / ${rows.length}` }),\n blocks: [\n {\n kind: 'metrics',\n items: [{ label: words('ai-assistant.read.count', 'rows'), value: String(rows.length), ...(complete ? {} : { note: `/ ${total}` }) }, ...sumColumns.map(column => ({ label: column.label, value: String(column.of(sums)) }))]\n },\n ...(groups\n ? [\n {\n kind: 'table',\n caption: words(target.columns.find(one => one.name === groupBy)?.labelKey, groupBy!),\n columns: [{ name: 'key', label: words(target.columns.find(one => one.name === groupBy)?.labelKey, groupBy!), type: 'string' }, { name: 'count', label: words('ai-assistant.read.count', 'rows'), type: 'number' }, ...sumColumns.map(column => ({ name: column.name, label: column.label, type: 'number' }))],\n rows: groups.map(group => ({ key: group.key, count: group.count, ...Object.fromEntries(sumColumns.map(column => [column.name, column.of(group.sums)])) }))\n }\n ]\n : []),\n { kind: 'table', caption: label, columns, rows }\n ]\n })\n return {\n proposed: true,\n kind: 'workspace',\n icon: 'table_view',\n label: title,\n ...said,\n forScreen: { workspace, contents: workspaceContents(workspace!) },\n message: `${rows.length} rows of ${total} are on the AI 작업판 as read - the person opens it from the card.${incomplete} Say the point in one or two lines from the sums, groups and rows above; do not write the table out.`\n }\n}\n\nexport function openScreen(target: ReadTarget, args: any, context: any) {\n const { criteria, refused } = readCriteria(target, args)\n if (refused.length) return { rejected: true, error: 'condition-unreadable', refused, message: 'fix the conditions and call again.' }\n const address = screenAddress(target, criteria)\n if (!address) return { rejected: true, error: 'no-screen', message: 'this list has no screen to open.' }\n const words = wordsOf(context)\n return {\n proposed: true,\n kind: 'open-page',\n icon: 'open_in_new',\n label: words(target.screen!.labelKey ?? target.labelKey, target.key),\n target: target.key,\n href: address.href,\n applied: address.applied,\n notApplied: address.notApplied,\n /* The card says them in the reader's words. */\n notAppliedLabels: address.notApplied.map(name => words(target.criteria.find(one => one.name === name)?.labelKey ?? (name === 'text' || name === 'id' ? `ai-assistant.read.${name}` : undefined), name)),\n message:\n 'the card opens the screen when the person presses it.' +\n (address.notApplied.length ? ` The screen does not take ${address.notApplied.join(', ')} - say so.` : '')\n }\n}\n\nexport function readCategoryOf(target: ReadTarget, run: (context: any) => GraphqlRunner = runAsCaller): ToolCategory {\n const door = rootFieldOf(target.query, 'query')\n const conditions = {\n ...Object.fromEntries(target.criteria.map(criterion => [criterion.name, criterionSchema(criterion)])),\n ...(target.search ? { text: { type: 'string', description: `words to find - ${target.search.description}` } } : {})\n }\n const specs: ToolSpec[] = [\n {\n kind: 'read',\n name: queryToolName(target.key),\n /* The person must be able to read the list on its screen - the tool is not a second way in. */\n doors: [door],\n description:\n `Read ${target.description} Set the conditions the question names. Returns the count, the sums, ` +\n `groups when groupBy is given (a date column groups by month) and the first ${ROWS_FOR_MODEL} rows; more rows go on the AI 작업판 as read.`,\n schema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'One record by its id, from an earlier answer - its detail.' },\n ...conditions,\n groupBy: { type: 'string', description: `One column to group by: ${target.columns.map(one => one.name).join(', ')}.` },\n show: { type: 'string', enum: ['answer', 'workspace'], description: 'workspace to put even a short result on the AI 작업판.' },\n title: { type: 'string', description: 'The workspace title, in the person\\'s language.' },\n name: { type: 'string', description: 'The workspace key; the same key again makes a new version.' }\n }\n },\n builder: (args: any, context: any) => queryRecords(target, args, context, run(context))\n } as ToolSpec,\n ...(target.screen\n ? [\n {\n kind: 'read',\n name: screenToolName(target.key),\n doors: [door],\n description: `Offer the person the screen that lists ${target.description} with these conditions. Reads nothing. The screen takes: ${target.screen.takes.join(', ')}.`,\n schema: { type: 'object', properties: conditions },\n builder: (args: any, context: any) => openScreen(target, args, context)\n } as ToolSpec\n ]\n : [])\n ]\n return {\n name: readCategoryName(target.key),\n description: `data read: ${target.key}`,\n guidance: [\n `- To answer from ${target.key} records - a list, or one record found by its name, code or id - call ${queryToolName(target.key)} with the conditions the question names. Every number you say comes from its result - never add up rows yourself; use its sums and groups.`,\n `- A list, a summary by item or month, or a comparison: call it with groupBy, and let a long result go on the AI 작업판 - then answer in one or two lines.`,\n `- When the result says complete: false, say how many of how many were read and ask to narrow - never call partial sums the total.`,\n ...(target.columns.some(one => one.currency)\n ? [`- Sums of ${target.columns.filter(one => one.currency).map(one => one.name).join(', ')} come per currency. Say each currency's sum; never add two currencies into one number. A comparison across currencies uses a rate you read, and says the rate and its date.`]\n : []),\n ...(target.screen ? [`- When the person wants to work on the records themselves (edit, sort, export), call ${screenToolName(target.key)}; say which conditions the screen does not take.`] : [])\n ].join('\\n'),\n specs\n }\n}\n\n/**\n * What an application calls at boot to let the assistant read one of its lists. A mode opens it by naming the key\n * in `readTargets`.\n */\nexport function registerReadTarget(target: ReadTarget): void {\n declareReadTarget(target)\n registerToolCategory(readCategoryOf(target))\n}\n\n/* ── One answer of a query (DetailRead) ───────────────────────────────────────────────────────────────────── */\n\nfunction argSchema(arg: DetailArg): any {\n const type = arg.type === 'number' ? 'number' : arg.type === 'integer' ? 'integer' : arg.type === 'boolean' ? 'boolean' : 'string'\n const said = [arg.description, arg.type === 'date' ? 'YYYY-MM-DD' : undefined, arg.type === 'enum' ? `one of: ${arg.values!.join(', ')}` : undefined].filter(Boolean).join('. ')\n return { type, ...(said ? { description: said } : {}) }\n}\n\n/** Runs the query as the person with the arguments the model set; the answer as the query returned it. */\nexport async function queryDetail(target: DetailRead, args: any, run: GraphqlRunner) {\n const variables: Record<string, unknown> = {}\n const refused: { name: string; code: string }[] = []\n for (const arg of target.args ?? []) {\n const value = args?.[arg.name]\n if (value === undefined || value === null || value === '') {\n if (arg.required) refused.push({ name: arg.name, code: 'required' })\n continue\n }\n const { read, code } = readFieldValue({ name: arg.name, type: arg.type === 'string' ? 'text' : arg.type, values: arg.values, axis: arg.axis } as any, value)\n if (read === undefined) refused.push({ name: arg.name, code: code ?? 'unreadable' })\n else variables[arg.name] = read\n }\n if (refused.length) return { rejected: true, error: 'argument-unreadable', refused, message: `these arguments are missing or do not fit their type: ${refused.map(one => `${one.name} (${one.code})`).join(', ')}. Fix them and call again.` }\n let answer\n try {\n answer = await run(target.query, variables)\n } catch (error: any) {\n return { rejected: true, error: 'query-failed', message: `it could not be read: ${error?.message ?? error}` }\n }\n if (answer.errors?.length) return { rejected: true, error: 'query-failed', message: `it could not be read: ${answer.errors.map(one => one.message).join('; ')}` }\n const root = rootFieldOf(target.query, 'query').replace(/^Query\\./, '')\n const value = answer.data?.[root]\n if (value === null || value === undefined) return { target: target.key, found: false, message: 'nothing was found for these arguments - say so; do not fill it in.' }\n const size = JSON.stringify(value).length\n if (size > MAX_DETAIL_CHARS) return { rejected: true, error: 'answer-too-large', size, message: `the answer runs to ${size} characters, more than ${MAX_DETAIL_CHARS} - narrow the arguments, or read the list it is made of.` }\n return { target: target.key, answer: value, message: 'answer from these fields; every number you say comes from them. Amounts are in the currency beside them - never add two currencies into one number.' }\n}\n\nexport function detailCategoryOf(target: DetailRead, run: (context: any) => GraphqlRunner = runAsCaller): ToolCategory {\n const door = rootFieldOf(target.query, 'query')\n const name = detailToolName(target.key)\n return {\n name: readCategoryName(target.key),\n description: `data read: ${target.key}`,\n guidance: `- To answer about ${target.description.replace(/\\.$/, '')}, call ${name}. Every number you say comes from its answer.`,\n specs: [\n {\n kind: 'read',\n name,\n /* The person must be able to run the query on its screen - the tool is not a second way in. */\n doors: [door],\n description: `Read ${target.description}`,\n schema: {\n type: 'object',\n ...((target.args ?? []).some(one => one.required) ? { required: (target.args ?? []).filter(one => one.required).map(one => one.name) } : {}),\n properties: Object.fromEntries((target.args ?? []).map(arg => [arg.name, argSchema(arg)]))\n },\n builder: (args: any, context: any) => queryDetail(target, args, run(context))\n } as ToolSpec\n ]\n }\n}\n\n/** What an application calls at boot to let the assistant read one answer of its API. A mode opens it by key in `readTargets`. */\nexport function registerDetailRead(target: DetailRead): void {\n declareDetailRead(target)\n registerToolCategory(detailCategoryOf(target))\n}\n"]}
1
+ {"version":3,"file":"read-tools.js","sourceRoot":"","sources":["../../../server/service/data-read/read-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * The tools of an AI 조회 target (operato-application/design/ai/read-targets.md §4, §5).\n *\n * query<X> reads the rows through the application's list query as the person, and tells the model the count, the\n * sums, the groups and a few rows. A longer result goes on the AI 작업판 as a proposal the server builds from the rows\n * themselves - the table is never written by the model. open<X>Screen reads nothing: it hands the card the address\n * of the application's list screen with the conditions it takes.\n */\nimport { registerToolCategory, type ToolCategory, type ToolSpec } from '@things-factory/ai-client-base'\n\nimport { readFieldValue, rootFieldOf } from '../data-entry/entry-target.js'\nimport type { GraphqlRunner } from '../data-entry/entry-update.js'\nimport { runAsCaller } from '../data-entry/entry-tools.js'\nimport { normalizeWorkspace, workspaceContents } from '../workspace/workspace-blocks.js'\nimport {\n declareReadTarget,\n filtersOf,\n currenciesOf,\n declareDetailRead,\n detailToolName,\n MAX_DETAIL_CHARS,\n type DetailArg,\n type DetailRead,\n groupsOf,\n queryToolName,\n readCategoryName,\n readCriteria,\n readRows,\n ROWS_FOR_MODEL,\n screenAddress,\n screenToolName,\n sumsOf,\n type ReadCriterion,\n type ReadTarget\n} from './read-target.js'\n\n/** The reader's words for a key - the key's own default when the translator has none. */\nconst wordsOf = (context: any) => (key: string | undefined, fallback: string) => {\n if (!key || typeof context?.t !== 'function') return fallback\n try {\n const said = context.t(key)\n return said && said !== key ? String(said) : fallback\n } catch {\n return fallback\n }\n}\n\nfunction criterionSchema(criterion: ReadCriterion): any {\n /* One type per field - Gemini's function schema refuses a list of types (2026-10-01). */\n const type = criterion.type === 'number' ? 'number' : criterion.type === 'integer' ? 'integer' : criterion.type === 'boolean' ? 'boolean' : 'string'\n const said = [criterion.description, criterion.type === 'date' ? 'YYYY-MM-DD' : undefined, criterion.type === 'enum' ? `one of: ${criterion.values!.join(', ')}` : undefined]\n .filter(Boolean)\n .join('. ')\n return { type, ...(said ? { description: said } : {}) }\n}\n\nexport async function queryRecords(target: ReadTarget, args: any, context: any, run: GraphqlRunner) {\n const { criteria, refused } = readCriteria(target, args)\n if (refused.length) {\n return { rejected: true, error: 'condition-unreadable', refused, message: `these conditions do not fit their type: ${refused.map(one => `${one.name} (${one.code})`).join(', ')}. Fix them and call again.` }\n }\n let read\n try {\n read = await readRows(target, filtersOf(target, criteria), run, typeof criteria.text === 'string' && target.search ? criteria.text : undefined)\n } catch (error: any) {\n return { rejected: true, error: 'query-failed', message: `the list could not be read: ${error?.message ?? error}` }\n }\n const { rows, total, complete } = read\n const sums = sumsOf(target, rows)\n const groupBy = typeof args?.groupBy === 'string' && args.groupBy ? args.groupBy : undefined\n const groups = groupBy ? groupsOf(target, rows, groupBy) : undefined\n const words = wordsOf(context)\n const label = words(target.labelKey, target.key)\n\n const said = {\n target: target.key,\n criteria,\n total,\n read: rows.length,\n complete,\n sums,\n ...(groupBy ? (groups ? { groupBy, groups: groups.slice(0, 50), ...(groups.length > 50 ? { moreGroups: groups.length - 50 } : {}) } : { groupBy, groupRefused: 'no such column' }) : {}),\n rows: rows.slice(0, ROWS_FOR_MODEL),\n ...(rows.length > ROWS_FOR_MODEL ? { rowsNotShown: rows.length - ROWS_FOR_MODEL } : {})\n }\n const incomplete = complete\n ? ''\n : ` Only ${rows.length} of ${total} rows were read; the sums and groups are of those rows, not of the list - say so, and ask the person to narrow the conditions.`\n\n if (rows.length === 1 && args?.show !== 'workspace') {\n return { ...said, record: rows[0], message: 'one record - answer from its fields; say a field it does not have as not recorded.' }\n }\n if (rows.length <= ROWS_FOR_MODEL && args?.show !== 'workspace') {\n return { ...said, message: `${rows.length} rows of ${total}.${incomplete} Answer from these rows; every number you say comes from them.` }\n }\n\n /* The workspace is built here from the rows as read - the model never copies the table. */\n const columns = target.columns.map(column => ({ name: column.name, label: words(column.labelKey, column.name), type: column.type }))\n const totalColumns = target.columns.filter(one => one.total)\n /* A sum per currency is one figure and one group column per currency it holds - 「계약금액 (USD)」. */\n const sumColumns = totalColumns.flatMap(column => {\n const label = words(column.labelKey, column.name)\n const codes = currenciesOf([sums, ...(groups ?? []).map(group => group.sums)], column.name)\n return column.currency\n ? codes.map(code => ({ name: `${column.name}:${code}`, label: `${label} (${code})`, of: (one: Record<string, any>) => one[column.name]?.[code] ?? 0 }))\n : [{ name: column.name, label, of: (one: Record<string, any>) => one[column.name] }]\n })\n const title = typeof args?.title === 'string' && args.title.trim() ? args.title.trim() : `${label} · ${rows.length}`\n const { workspace } = normalizeWorkspace({\n name: typeof args?.name === 'string' && args.name ? args.name : target.key.replace(/\\./g, '-'),\n title,\n ...(complete ? {} : { summary: `${total} / ${rows.length}` }),\n blocks: [\n {\n kind: 'metrics',\n items: [{ label: words('ai-assistant.read.count', 'rows'), value: String(rows.length), ...(complete ? {} : { note: `/ ${total}` }) }, ...sumColumns.map(column => ({ label: column.label, value: String(column.of(sums)) }))]\n },\n ...(groups\n ? [\n {\n kind: 'table',\n caption: words(target.columns.find(one => one.name === groupBy)?.labelKey, groupBy!),\n columns: [{ name: 'key', label: words(target.columns.find(one => one.name === groupBy)?.labelKey, groupBy!), type: 'string' }, { name: 'count', label: words('ai-assistant.read.count', 'rows'), type: 'number' }, ...sumColumns.map(column => ({ name: column.name, label: column.label, type: 'number' }))],\n rows: groups.map(group => ({ key: group.key, count: group.count, ...Object.fromEntries(sumColumns.map(column => [column.name, column.of(group.sums)])) }))\n }\n ]\n : []),\n { kind: 'table', caption: label, columns, rows }\n ]\n })\n return {\n proposed: true,\n kind: 'workspace',\n icon: 'table_view',\n label: title,\n ...said,\n forScreen: { workspace, contents: workspaceContents(workspace!) },\n message: `${rows.length} rows of ${total} are on the AI 작업판 as read - the person opens it from the card.${incomplete} Say the point in one or two lines from the sums, groups and rows above; do not write the table out.`\n }\n}\n\nexport function openScreen(target: ReadTarget, args: any, context: any) {\n const { criteria, refused } = readCriteria(target, args)\n if (refused.length) return { rejected: true, error: 'condition-unreadable', refused, message: 'fix the conditions and call again.' }\n const address = screenAddress(target, criteria)\n if (!address) return { rejected: true, error: 'no-screen', message: 'this list has no screen to open.' }\n const words = wordsOf(context)\n return {\n proposed: true,\n kind: 'open-page',\n icon: 'open_in_new',\n label: words(target.screen!.labelKey ?? target.labelKey, target.key),\n target: target.key,\n href: address.href,\n applied: address.applied,\n notApplied: address.notApplied,\n /* The card says them in the reader's words. */\n notAppliedLabels: address.notApplied.map(name => words(target.criteria.find(one => one.name === name)?.labelKey ?? (name === 'text' || name === 'id' ? `ai-assistant.read.${name}` : undefined), name)),\n message:\n 'the card opens the screen when the person presses it.' +\n (address.notApplied.length ? ` The screen does not take ${address.notApplied.join(', ')} - say so.` : '')\n }\n}\n\nexport function readCategoryOf(target: ReadTarget, run: (context: any) => GraphqlRunner = runAsCaller): ToolCategory {\n const door = rootFieldOf(target.query, 'query')\n const conditions = {\n ...Object.fromEntries(target.criteria.map(criterion => [criterion.name, criterionSchema(criterion)])),\n ...(target.search ? { text: { type: 'string', description: `words to find - ${target.search.description}` } } : {})\n }\n const specs: ToolSpec[] = [\n {\n kind: 'read',\n name: queryToolName(target.key),\n /* The person must be able to read the list on its screen - the tool is not a second way in. */\n doors: [door],\n description:\n `Read ${target.description} Set the conditions the question names. Returns the count, the sums, ` +\n `groups when groupBy is given (a date column groups by month) and the first ${ROWS_FOR_MODEL} rows; more rows go on the AI 작업판 as read.`,\n schema: {\n type: 'object',\n properties: {\n id: { type: 'string', description: 'One record by its id, from an earlier answer - its detail.' },\n ...conditions,\n groupBy: { type: 'string', description: `One column to group by: ${target.columns.map(one => one.name).join(', ')}.` },\n show: { type: 'string', enum: ['answer', 'workspace'], description: 'workspace to put even a short result on the AI 작업판.' },\n title: { type: 'string', description: 'The workspace title, in the person\\'s language.' },\n name: { type: 'string', description: 'The workspace key; the same key again makes a new version.' }\n }\n },\n builder: (args: any, context: any) => queryRecords(target, args, context, run(context))\n } as ToolSpec,\n ...(target.screen\n ? [\n {\n kind: 'read',\n name: screenToolName(target.key),\n doors: [door],\n description: `Offer the person the screen that lists ${target.description} with these conditions. Reads nothing. The screen takes: ${target.screen.takes.join(', ')}.`,\n schema: { type: 'object', properties: conditions },\n builder: (args: any, context: any) => openScreen(target, args, context)\n } as ToolSpec\n ]\n : [])\n ]\n return {\n name: readCategoryName(target.key),\n description: `data read: ${target.key}`,\n guidance: [\n `- To answer from ${target.key} records - a list, or one record found by its name, code or id - call ${queryToolName(target.key)} with the conditions the question names. Every number you say comes from its result - never add up rows yourself; use its sums and groups.`,\n `- A list, a summary by item or month, or a comparison: call it with groupBy, and let a long result go on the AI 작업판 - then answer in one or two lines.`,\n `- When the result says complete: false, say how many of how many were read and ask to narrow - never call partial sums the total.`,\n ...(target.columns.some(one => one.currency)\n ? [`- Sums of ${target.columns.filter(one => one.currency).map(one => one.name).join(', ')} come per currency. Say each currency's sum; never add two currencies into one number. A comparison across currencies uses a rate you read, and says the rate and its date.`]\n : []),\n ...(target.screen ? [`- When the person wants to work on the records themselves (edit, sort, export), call ${screenToolName(target.key)}; say which conditions the screen does not take.`] : [])\n ].join('\\n'),\n specs\n }\n}\n\n/**\n * What an application calls at boot to let the assistant read one of its lists. A mode opens it by naming the key\n * in `readTargets`.\n */\nexport function registerReadTarget(target: ReadTarget): void {\n declareReadTarget(target)\n registerToolCategory(readCategoryOf(target))\n}\n\n/* ── One answer of a query (DetailRead) ───────────────────────────────────────────────────────────────────── */\n\nfunction argSchema(arg: DetailArg): any {\n const type = arg.type === 'number' ? 'number' : arg.type === 'integer' ? 'integer' : arg.type === 'boolean' ? 'boolean' : 'string'\n const said = [arg.description, arg.type === 'date' ? 'YYYY-MM-DD' : undefined, arg.type === 'enum' ? `one of: ${arg.values!.join(', ')}` : undefined].filter(Boolean).join('. ')\n return { type, ...(said ? { description: said } : {}) }\n}\n\n/**\n * What running a detail read as the person gave - the root field's value, or why there is none. Shared by the tool,\n * which hands the value to the model, and by every other reader of a detail read (a dashboard card, ADR-0160\n * decision 2), which has its own limits: the arguments, the door and the query are one, the size rule is the tool's.\n */\nexport interface DetailRun {\n /** The root field's value - absent when `error` says why. */\n value?: unknown\n error?: 'argument-unreadable' | 'query-failed' | 'not-found'\n refused?: { name: string; code: string }[]\n message?: string\n}\n\n/** Runs the query as the person with the arguments given - read by their declared types, a missing required one refused. */\nexport async function runDetail(target: DetailRead, args: any, run: GraphqlRunner): Promise<DetailRun> {\n const variables: Record<string, unknown> = {}\n const refused: { name: string; code: string }[] = []\n for (const arg of target.args ?? []) {\n const value = args?.[arg.name]\n if (value === undefined || value === null || value === '') {\n if (arg.required) refused.push({ name: arg.name, code: 'required' })\n continue\n }\n const { read, code } = readFieldValue({ name: arg.name, type: arg.type === 'string' ? 'text' : arg.type, values: arg.values, axis: arg.axis } as any, value)\n if (read === undefined) refused.push({ name: arg.name, code: code ?? 'unreadable' })\n else variables[arg.name] = read\n }\n if (refused.length) return { error: 'argument-unreadable', refused }\n let answer\n try {\n answer = await run(target.query, variables)\n } catch (error: any) {\n return { error: 'query-failed', message: String(error?.message ?? error) }\n }\n if (answer.errors?.length) return { error: 'query-failed', message: answer.errors.map(one => one.message).join('; ') }\n const root = rootFieldOf(target.query, 'query').replace(/^Query\\./, '')\n const value = answer.data?.[root]\n if (value === null || value === undefined) return { error: 'not-found' }\n return { value }\n}\n\n/** Runs the query as the person with the arguments the model set; the answer as the query returned it. */\nexport async function queryDetail(target: DetailRead, args: any, run: GraphqlRunner) {\n const ran = await runDetail(target, args, run)\n if (ran.error) {\n if (ran.error === 'argument-unreadable')\n return { rejected: true, error: 'argument-unreadable', refused: ran.refused, message: `these arguments are missing or do not fit their type: ${ran.refused.map(one => `${one.name} (${one.code})`).join(', ')}. Fix them and call again.` }\n if (ran.error === 'query-failed') return { rejected: true, error: 'query-failed', message: `it could not be read: ${ran.message}` }\n return { target: target.key, found: false, message: 'nothing was found for these arguments - say so; do not fill it in.' }\n }\n const value = ran.value\n const size = JSON.stringify(value).length\n if (size > MAX_DETAIL_CHARS) return { rejected: true, error: 'answer-too-large', size, message: `the answer runs to ${size} characters, more than ${MAX_DETAIL_CHARS} - narrow the arguments, or read the list it is made of.` }\n return { target: target.key, answer: value, message: 'answer from these fields; every number you say comes from them. Amounts are in the currency beside them - never add two currencies into one number.' }\n}\n\nexport function detailCategoryOf(target: DetailRead, run: (context: any) => GraphqlRunner = runAsCaller): ToolCategory {\n const door = rootFieldOf(target.query, 'query')\n const name = detailToolName(target.key)\n return {\n name: readCategoryName(target.key),\n description: `data read: ${target.key}`,\n guidance: `- To answer about ${target.description.replace(/\\.$/, '')}, call ${name}. Every number you say comes from its answer.`,\n specs: [\n {\n kind: 'read',\n name,\n /* The person must be able to run the query on its screen - the tool is not a second way in. */\n doors: [door],\n description: `Read ${target.description}`,\n schema: {\n type: 'object',\n ...((target.args ?? []).some(one => one.required) ? { required: (target.args ?? []).filter(one => one.required).map(one => one.name) } : {}),\n properties: Object.fromEntries((target.args ?? []).map(arg => [arg.name, argSchema(arg)]))\n },\n builder: (args: any, context: any) => queryDetail(target, args, run(context))\n } as ToolSpec\n ]\n }\n}\n\n/** What an application calls at boot to let the assistant read one answer of its API. A mode opens it by key in `readTargets`. */\nexport function registerDetailRead(target: DetailRead): void {\n declareDetailRead(target)\n registerToolCategory(detailCategoryOf(target))\n}\n"]}
@@ -11,6 +11,7 @@ import './chat-session/session-purge.js';
11
11
  import './chat-session/attachment-route.js';
12
12
  import { EntryProposalResolver } from './data-entry/entry-resolver.js';
13
13
  import './workspace/workspace-tools.js';
14
+ import './people/index.js';
14
15
  export * from './types.js';
15
16
  export * from './chat-session-resolver.js';
16
17
  export * from './assistant-chat-resolver.js';
@@ -22,8 +23,9 @@ export * from './data-entry/entry-target.js';
22
23
  export { registerEntryTarget, entryCategoryOf, runAsCaller } from './data-entry/entry-tools.js';
23
24
  export { proposeChanges, MAX_CHANGES } from './data-entry/entry-update.js';
24
25
  export * from './data-read/read-target.js';
25
- export { registerReadTarget, readCategoryOf, registerDetailRead, detailCategoryOf } from './data-read/read-tools.js';
26
+ export { registerReadTarget, readCategoryOf, registerDetailRead, detailCategoryOf, runDetail, type DetailRun } from './data-read/read-tools.js';
26
27
  export * from './data-read/list-read.js';
28
+ export * from './people/index.js';
27
29
  export * from './workspace/workspace-blocks.js';
28
30
  export * from './grounding-sources.js';
29
31
  export * from './chat-session/session-anchor.js';
@@ -45,6 +47,8 @@ export * from './chat-session-participant/mention-invite.js';
45
47
  export * from './chat-session-participant/presence.js';
46
48
  export * from './chat-message/index.js';
47
49
  export * from './chat-session-participant/index.js';
50
+ export { PROPOSAL_OUTCOME_PREFIX } from './chat-message/proposal-outcome.js';
51
+ export { assertMayWriteSession } from './chat-session/session-write-gate.js';
48
52
  export * from './unattended-run/index.js';
49
53
  export declare const entities: (typeof import("./chat-message/chat-message.js").ChatMessage | typeof import("./chat-session/chat-session.js").ChatSession | typeof import("./chat-session-participant/chat-session-participant.js").ChatSessionParticipant | typeof import("./unattended-run/assistant-run.js").AssistantRun)[];
50
54
  export declare const schema: {
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.schema = exports.entities = exports.detailCategoryOf = exports.registerDetailRead = exports.readCategoryOf = exports.registerReadTarget = exports.MAX_CHANGES = exports.proposeChanges = exports.runAsCaller = exports.entryCategoryOf = exports.registerEntryTarget = exports.requestTranslator = void 0;
3
+ exports.schema = exports.entities = exports.assertMayWriteSession = exports.PROPOSAL_OUTCOME_PREFIX = exports.runDetail = exports.detailCategoryOf = exports.registerDetailRead = exports.readCategoryOf = exports.registerReadTarget = exports.MAX_CHANGES = exports.proposeChanges = exports.runAsCaller = exports.entryCategoryOf = exports.registerEntryTarget = exports.requestTranslator = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const chat_session_resolver_js_1 = require("./chat-session-resolver.js");
6
6
  const assistant_chat_resolver_js_1 = require("./assistant-chat-resolver.js");
@@ -18,6 +18,8 @@ require("./chat-session/session-purge.js");
18
18
  require("./chat-session/attachment-route.js");
19
19
  const entry_resolver_js_1 = require("./data-entry/entry-resolver.js");
20
20
  require("./workspace/workspace-tools.js");
21
+ /* Who works here, and the card that brings one of them into a conversation - every conversation carries both. */
22
+ require("./people/index.js");
21
23
  const index_js_4 = require("./unattended-run/index.js");
22
24
  tslib_1.__exportStar(require("./types.js"), exports);
23
25
  tslib_1.__exportStar(require("./chat-session-resolver.js"), exports);
@@ -49,7 +51,9 @@ Object.defineProperty(exports, "registerReadTarget", { enumerable: true, get: fu
49
51
  Object.defineProperty(exports, "readCategoryOf", { enumerable: true, get: function () { return read_tools_js_1.readCategoryOf; } });
50
52
  Object.defineProperty(exports, "registerDetailRead", { enumerable: true, get: function () { return read_tools_js_1.registerDetailRead; } });
51
53
  Object.defineProperty(exports, "detailCategoryOf", { enumerable: true, get: function () { return read_tools_js_1.detailCategoryOf; } });
54
+ Object.defineProperty(exports, "runDetail", { enumerable: true, get: function () { return read_tools_js_1.runDetail; } });
52
55
  tslib_1.__exportStar(require("./data-read/list-read.js"), exports);
56
+ tslib_1.__exportStar(require("./people/index.js"), exports);
53
57
  /* The AI 작업판 - large results on a page of their own (design/ai/workspace.md). */
54
58
  tslib_1.__exportStar(require("./workspace/workspace-blocks.js"), exports);
55
59
  /* 무엇이 근거인가 — 도구 결과 밖의 셋(프롬프트 · 대화 · 화면 스냅숏). */
@@ -78,6 +82,11 @@ tslib_1.__exportStar(require("./chat-session-participant/mention-invite.js"), ex
78
82
  tslib_1.__exportStar(require("./chat-session-participant/presence.js"), exports);
79
83
  tslib_1.__exportStar(require("./chat-message/index.js"), exports);
80
84
  tslib_1.__exportStar(require("./chat-session-participant/index.js"), exports);
85
+ /* Reading the stored proposals of a conversation and whether one is answered - a package that applies its own card reads them as entry does. */
86
+ var proposal_outcome_js_1 = require("./chat-message/proposal-outcome.js");
87
+ Object.defineProperty(exports, "PROPOSAL_OUTCOME_PREFIX", { enumerable: true, get: function () { return proposal_outcome_js_1.PROPOSAL_OUTCOME_PREFIX; } });
88
+ var session_write_gate_js_1 = require("./chat-session/session-write-gate.js");
89
+ Object.defineProperty(exports, "assertMayWriteSession", { enumerable: true, get: function () { return session_write_gate_js_1.assertMayWriteSession; } });
81
90
  /* A mode run with no person in it - a scheduled draft (operato-application/design/ai/unattended-run.md). */
82
91
  tslib_1.__exportStar(require("./unattended-run/index.js"), exports);
83
92
  exports.entities = [...index_js_1.entities, ...index_js_2.entities, ...index_js_3.entities, ...index_js_4.entities];
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,yEAAgE;AAChE,6EAAoE;AACpE,4FAAmF;AACnF,yFAAgF;AAChF,iEAAwD;AACxD,sGAA+F;AAC/F,8FAAqF;AACrF,4FAAmF;AACnF,sDAAyE;AACzE,sDAAyE;AACzE,kEAAgG;AAChG,8CAA2C;AAC3C,2CAAwC;AACxC,8CAA2C;AAC3C,sEAAsE;AACtE,0CAAuC;AACvC,wDAA6E;AAE7E,qDAA0B;AAC1B,qEAA0C;AAC1C,uEAA4C;AAC5C,oGAAoG;AACpG,oEAAyC;AACzC,iEAA2D;AAAlD,0HAAA,iBAAiB,OAAA;AAC1B,6EAAkD;AAClD;;;GAGG;AACH,2DAAgC;AAChC,+GAA+G;AAC/G,uEAA4C;AAC5C,8DAA+F;AAAtF,qHAAA,mBAAmB,OAAA;AAAE,iHAAA,eAAe,OAAA;AAAE,6GAAA,WAAW,OAAA;AAC1D,yHAAyH;AACzH,gEAA0E;AAAjE,iHAAA,cAAc,OAAA;AAAE,8GAAA,WAAW,OAAA;AACpC,uHAAuH;AACvH,qEAA0C;AAC1C,2DAAoH;AAA3G,mHAAA,kBAAkB,OAAA;AAAE,+GAAA,cAAc,OAAA;AAAE,mHAAA,kBAAkB,OAAA;AAAE,iHAAA,gBAAgB,OAAA;AACjF,mEAAwC;AACxC,iFAAiF;AACjF,0EAA+C;AAC/C,gDAAgD;AAChD,iEAAsC;AACtC,sDAAsD;AACtD,2EAAgD;AAChD,gHAAgH;AAChH,+EAAoD;AACpD,kEAAuC;AACvC,8DAA8D;AAC9D,0EAA+C;AAC/C,8EAAmD;AACnD,0EAA+C;AAC/C,qFAA0D;AAC1D,uFAA4D;AAC5D,wEAA6C;AAC7C,4EAAiD;AACjD,yEAA8C;AAC9C,wDAAwD;AACxD,iFAAsD;AACtD,iFAAsD;AACtD,mFAAwD;AACxD,4FAAiE;AACjE,2DAA2D;AAC3D,uFAA4D;AAC5D,iFAAsD;AACtD,kEAAuC;AACvC,8EAAmD;AACnD,4GAA4G;AAC5G,oEAAyC;AAE5B,QAAA,QAAQ,GAAG,CAAC,GAAG,mBAAmB,EAAE,GAAG,mBAAmB,EAAE,GAAG,mBAA8B,EAAE,GAAG,mBAAqB,CAAC,CAAA;AAExH,QAAA,MAAM,GAAG;IACpB,eAAe,EAAE;QACf,8CAAmB;QACnB,sDAAsD;QACtD,kDAAqB;QACrB,uDAAuD;QACvD,kDAAqB;QACrB,wDAAwD;QACxD,8DAA2B;QAC3B,mGAAmG;QACnG,sCAAe;QACf,sDAAuB;QACvB,wDAAwD;QACxD,oDAAsB;QACtB,qDAAqD;QACrD,gEAA6B;QAC7B,mDAAmD;QACnD,yCAAqB;KACtB;CACF,CAAA","sourcesContent":["import { ChatSessionResolver } from './chat-session-resolver.js'\nimport { AssistantChatResolver } from './assistant-chat-resolver.js'\nimport { AssistantModeResolver } from './assistant-mode/assistant-mode-resolver.js'\nimport { AssistantCapabilityResolver } from './assistant-capability-resolver.js'\nimport { AiAgentResolver } from './ai-agent-resolver.js'\nimport { MySessionActivitySubscription } from './chat-session/session-activity-subscription.js'\nimport { ChatMessageSubscription } from './chat-message/chat-message-subscription.js'\nimport { ChatTypingSubscription } from './chat-message/chat-typing-subscription.js'\nimport { entities as ChatSessionEntities } from './chat-session/index.js'\nimport { entities as ChatMessageEntities } from './chat-message/index.js'\nimport { entities as ChatSessionParticipantEntities } from './chat-session-participant/index.js'\nimport './chat-session/attachment-tools.js'\nimport './chat-session/session-purge.js'\nimport './chat-session/attachment-route.js'\nimport { EntryProposalResolver } from './data-entry/entry-resolver.js'\nimport './workspace/workspace-tools.js'\nimport { entities as UnattendedRunEntities } from './unattended-run/index.js'\n\nexport * from './types.js'\nexport * from './chat-session-resolver.js'\nexport * from './assistant-chat-resolver.js'\n/* The mode registry — each app server declares what its conversations are (ADR-0061 decision 7). */\nexport * from './assistant-mode/index.js'\nexport { requestTranslator } from './request-translator.js'\nexport * from './assistant-capability-resolver.js'\n/*\n * 대화 각본 하네스는 **런타임 export 에서 뺀다**(ADR-0070 A15 결정 ④) — 시험 도구가 서버 번들에\n * 실린다. 시험은 경로로 가져온다: `…/service/testing/conversation-script.js`.\n */\nexport * from './tool-access.js'\n/* Data entry from material - an app registers what it can enter; a mode names it (design/ai/data-entry.md). */\nexport * from './data-entry/entry-target.js'\nexport { registerEntryTarget, entryCategoryOf, runAsCaller } from './data-entry/entry-tools.js'\n/* An application's tool that prepares many changes at once makes the same change card the model's would (2026-10-24). */\nexport { proposeChanges, MAX_CHANGES } from './data-entry/entry-update.js'\n/* Reading an application's lists - an app registers what it lets read; a mode names it (design/ai/read-targets.md). */\nexport * from './data-read/read-target.js'\nexport { registerReadTarget, readCategoryOf, registerDetailRead, detailCategoryOf } from './data-read/read-tools.js'\nexport * from './data-read/list-read.js'\n/* The AI 작업판 - large results on a page of their own (design/ai/workspace.md). */\nexport * from './workspace/workspace-blocks.js'\n/* 무엇이 근거인가 — 도구 결과 밖의 셋(프롬프트 · 대화 · 화면 스냅숏). */\nexport * from './grounding-sources.js'\n/* 앵커 순수 로직 — 호스트가 앵커 종류를 참조한다(리졸버는 데코레이터 때문에 무겁다). */\nexport * from './chat-session/session-anchor.js'\n/* Who may read a conversation — one rule, also asked by doors outside this package (board-ai's revertPatch). */\nexport * from './chat-session/session-visibility.js'\nexport * from './chat-session/index.js'\n/* 순수 로직들 — 호스트(board-ai 등)가 같은 규칙을 쓰라고 공개한다. 베끼면 한쪽만 고쳐진다. */\nexport * from './chat-session/session-inbox.js'\nexport * from './chat-session/attachment-policy.js'\nexport * from './chat-session/session-purge.js'\nexport * from './chat-session/session-activity-publish.js'\nexport * from './chat-session/session-activity-broadcast.js'\nexport * from './chat-message/llm-history.js'\nexport * from './chat-message/history-summary.js'\nexport * from './chat-message/fold-history.js'\n/* 상한 밖으로 밀려난 앞부분을 요약으로 접는 orchestration — 중립 문이 부른다. */\nexport * from './chat-message/fold-session-history.js'\nexport * from './chat-message/chat-message-publish.js'\nexport * from './chat-message/chat-message-broadcast.js'\nexport * from './chat-session-participant/invite-notification.js'\n/* 멘션이 사람을 불러들이는 자리 — 사람의 말을 저장하는 문만 부른다(ADR-0071 결정 1). */\nexport * from './chat-session-participant/mention-invite.js'\nexport * from './chat-session-participant/presence.js'\nexport * from './chat-message/index.js'\nexport * from './chat-session-participant/index.js'\n/* A mode run with no person in it - a scheduled draft (operato-application/design/ai/unattended-run.md). */\nexport * from './unattended-run/index.js'\n\nexport const entities = [...ChatSessionEntities, ...ChatMessageEntities, ...ChatSessionParticipantEntities, ...UnattendedRunEntities]\n\nexport const schema = {\n resolverClasses: [\n ChatSessionResolver,\n /* 문서를 갖지 않은 표면의 대화 — board 를 안 싣는 제품이 물어볼 수 있는 자리. */\n AssistantChatResolver,\n /* 화면이 자기 대화가 무엇을 주는지 묻는 자리 — 문구는 서버가 요청 로케일로 옮겨 낸다. */\n AssistantModeResolver,\n /* 「이 배포에 AI 가 있나 · 무엇이 선언 없이 등록됐나」 — 창구 하나(표준 A7-a). */\n AssistantCapabilityResolver,\n /* A domain's AI agents - the settings card and the dock's picker (design/ai/agent-settings.md). */\n AiAgentResolver,\n ChatMessageSubscription,\n /* 「입력 중」 — 저장하지 않는 방의 한 줄. 듣는 사람은 메시지와 같은 방 판정을 지난다. */\n ChatTypingSubscription,\n /* 내가 참여한 모든 세션의 활동 — 창을 닫아 둔 표면이 배지·목록을 갱신할 수 있게. */\n MySessionActivitySubscription,\n /* 사람이 누른 입력 제안을 쓰는 자리 — 행마다 앱의 코드로, 그 사람의 권한으로. */\n EntryProposalResolver\n ]\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../server/service/index.ts"],"names":[],"mappings":";;;;AAAA,yEAAgE;AAChE,6EAAoE;AACpE,4FAAmF;AACnF,yFAAgF;AAChF,iEAAwD;AACxD,sGAA+F;AAC/F,8FAAqF;AACrF,4FAAmF;AACnF,sDAAyE;AACzE,sDAAyE;AACzE,kEAAgG;AAChG,8CAA2C;AAC3C,2CAAwC;AACxC,8CAA2C;AAC3C,sEAAsE;AACtE,0CAAuC;AACvC,iHAAiH;AACjH,6BAA0B;AAC1B,wDAA6E;AAE7E,qDAA0B;AAC1B,qEAA0C;AAC1C,uEAA4C;AAC5C,oGAAoG;AACpG,oEAAyC;AACzC,iEAA2D;AAAlD,0HAAA,iBAAiB,OAAA;AAC1B,6EAAkD;AAClD;;;GAGG;AACH,2DAAgC;AAChC,+GAA+G;AAC/G,uEAA4C;AAC5C,8DAA+F;AAAtF,qHAAA,mBAAmB,OAAA;AAAE,iHAAA,eAAe,OAAA;AAAE,6GAAA,WAAW,OAAA;AAC1D,yHAAyH;AACzH,gEAA0E;AAAjE,iHAAA,cAAc,OAAA;AAAE,8GAAA,WAAW,OAAA;AACpC,uHAAuH;AACvH,qEAA0C;AAC1C,2DAA+I;AAAtI,mHAAA,kBAAkB,OAAA;AAAE,+GAAA,cAAc,OAAA;AAAE,mHAAA,kBAAkB,OAAA;AAAE,iHAAA,gBAAgB,OAAA;AAAE,0GAAA,SAAS,OAAA;AAC5F,mEAAwC;AACxC,4DAAiC;AACjC,iFAAiF;AACjF,0EAA+C;AAC/C,gDAAgD;AAChD,iEAAsC;AACtC,sDAAsD;AACtD,2EAAgD;AAChD,gHAAgH;AAChH,+EAAoD;AACpD,kEAAuC;AACvC,8DAA8D;AAC9D,0EAA+C;AAC/C,8EAAmD;AACnD,0EAA+C;AAC/C,qFAA0D;AAC1D,uFAA4D;AAC5D,wEAA6C;AAC7C,4EAAiD;AACjD,yEAA8C;AAC9C,wDAAwD;AACxD,iFAAsD;AACtD,iFAAsD;AACtD,mFAAwD;AACxD,4FAAiE;AACjE,2DAA2D;AAC3D,uFAA4D;AAC5D,iFAAsD;AACtD,kEAAuC;AACvC,8EAAmD;AACnD,gJAAgJ;AAChJ,0EAA4E;AAAnE,8HAAA,uBAAuB,OAAA;AAChC,8EAA4E;AAAnE,8HAAA,qBAAqB,OAAA;AAC9B,4GAA4G;AAC5G,oEAAyC;AAE5B,QAAA,QAAQ,GAAG,CAAC,GAAG,mBAAmB,EAAE,GAAG,mBAAmB,EAAE,GAAG,mBAA8B,EAAE,GAAG,mBAAqB,CAAC,CAAA;AAExH,QAAA,MAAM,GAAG;IACpB,eAAe,EAAE;QACf,8CAAmB;QACnB,sDAAsD;QACtD,kDAAqB;QACrB,uDAAuD;QACvD,kDAAqB;QACrB,wDAAwD;QACxD,8DAA2B;QAC3B,mGAAmG;QACnG,sCAAe;QACf,sDAAuB;QACvB,wDAAwD;QACxD,oDAAsB;QACtB,qDAAqD;QACrD,gEAA6B;QAC7B,mDAAmD;QACnD,yCAAqB;KACtB;CACF,CAAA","sourcesContent":["import { ChatSessionResolver } from './chat-session-resolver.js'\nimport { AssistantChatResolver } from './assistant-chat-resolver.js'\nimport { AssistantModeResolver } from './assistant-mode/assistant-mode-resolver.js'\nimport { AssistantCapabilityResolver } from './assistant-capability-resolver.js'\nimport { AiAgentResolver } from './ai-agent-resolver.js'\nimport { MySessionActivitySubscription } from './chat-session/session-activity-subscription.js'\nimport { ChatMessageSubscription } from './chat-message/chat-message-subscription.js'\nimport { ChatTypingSubscription } from './chat-message/chat-typing-subscription.js'\nimport { entities as ChatSessionEntities } from './chat-session/index.js'\nimport { entities as ChatMessageEntities } from './chat-message/index.js'\nimport { entities as ChatSessionParticipantEntities } from './chat-session-participant/index.js'\nimport './chat-session/attachment-tools.js'\nimport './chat-session/session-purge.js'\nimport './chat-session/attachment-route.js'\nimport { EntryProposalResolver } from './data-entry/entry-resolver.js'\nimport './workspace/workspace-tools.js'\n/* Who works here, and the card that brings one of them into a conversation - every conversation carries both. */\nimport './people/index.js'\nimport { entities as UnattendedRunEntities } from './unattended-run/index.js'\n\nexport * from './types.js'\nexport * from './chat-session-resolver.js'\nexport * from './assistant-chat-resolver.js'\n/* The mode registry — each app server declares what its conversations are (ADR-0061 decision 7). */\nexport * from './assistant-mode/index.js'\nexport { requestTranslator } from './request-translator.js'\nexport * from './assistant-capability-resolver.js'\n/*\n * 대화 각본 하네스는 **런타임 export 에서 뺀다**(ADR-0070 A15 결정 ④) — 시험 도구가 서버 번들에\n * 실린다. 시험은 경로로 가져온다: `…/service/testing/conversation-script.js`.\n */\nexport * from './tool-access.js'\n/* Data entry from material - an app registers what it can enter; a mode names it (design/ai/data-entry.md). */\nexport * from './data-entry/entry-target.js'\nexport { registerEntryTarget, entryCategoryOf, runAsCaller } from './data-entry/entry-tools.js'\n/* An application's tool that prepares many changes at once makes the same change card the model's would (2026-10-24). */\nexport { proposeChanges, MAX_CHANGES } from './data-entry/entry-update.js'\n/* Reading an application's lists - an app registers what it lets read; a mode names it (design/ai/read-targets.md). */\nexport * from './data-read/read-target.js'\nexport { registerReadTarget, readCategoryOf, registerDetailRead, detailCategoryOf, runDetail, type DetailRun } from './data-read/read-tools.js'\nexport * from './data-read/list-read.js'\nexport * from './people/index.js'\n/* The AI 작업판 - large results on a page of their own (design/ai/workspace.md). */\nexport * from './workspace/workspace-blocks.js'\n/* 무엇이 근거인가 — 도구 결과 밖의 셋(프롬프트 · 대화 · 화면 스냅숏). */\nexport * from './grounding-sources.js'\n/* 앵커 순수 로직 — 호스트가 앵커 종류를 참조한다(리졸버는 데코레이터 때문에 무겁다). */\nexport * from './chat-session/session-anchor.js'\n/* Who may read a conversation — one rule, also asked by doors outside this package (board-ai's revertPatch). */\nexport * from './chat-session/session-visibility.js'\nexport * from './chat-session/index.js'\n/* 순수 로직들 — 호스트(board-ai 등)가 같은 규칙을 쓰라고 공개한다. 베끼면 한쪽만 고쳐진다. */\nexport * from './chat-session/session-inbox.js'\nexport * from './chat-session/attachment-policy.js'\nexport * from './chat-session/session-purge.js'\nexport * from './chat-session/session-activity-publish.js'\nexport * from './chat-session/session-activity-broadcast.js'\nexport * from './chat-message/llm-history.js'\nexport * from './chat-message/history-summary.js'\nexport * from './chat-message/fold-history.js'\n/* 상한 밖으로 밀려난 앞부분을 요약으로 접는 orchestration — 중립 문이 부른다. */\nexport * from './chat-message/fold-session-history.js'\nexport * from './chat-message/chat-message-publish.js'\nexport * from './chat-message/chat-message-broadcast.js'\nexport * from './chat-session-participant/invite-notification.js'\n/* 멘션이 사람을 불러들이는 자리 — 사람의 말을 저장하는 문만 부른다(ADR-0071 결정 1). */\nexport * from './chat-session-participant/mention-invite.js'\nexport * from './chat-session-participant/presence.js'\nexport * from './chat-message/index.js'\nexport * from './chat-session-participant/index.js'\n/* Reading the stored proposals of a conversation and whether one is answered - a package that applies its own card reads them as entry does. */\nexport { PROPOSAL_OUTCOME_PREFIX } from './chat-message/proposal-outcome.js'\nexport { assertMayWriteSession } from './chat-session/session-write-gate.js'\n/* A mode run with no person in it - a scheduled draft (operato-application/design/ai/unattended-run.md). */\nexport * from './unattended-run/index.js'\n\nexport const entities = [...ChatSessionEntities, ...ChatMessageEntities, ...ChatSessionParticipantEntities, ...UnattendedRunEntities]\n\nexport const schema = {\n resolverClasses: [\n ChatSessionResolver,\n /* 문서를 갖지 않은 표면의 대화 — board 를 안 싣는 제품이 물어볼 수 있는 자리. */\n AssistantChatResolver,\n /* 화면이 자기 대화가 무엇을 주는지 묻는 자리 — 문구는 서버가 요청 로케일로 옮겨 낸다. */\n AssistantModeResolver,\n /* 「이 배포에 AI 가 있나 · 무엇이 선언 없이 등록됐나」 — 창구 하나(표준 A7-a). */\n AssistantCapabilityResolver,\n /* A domain's AI agents - the settings card and the dock's picker (design/ai/agent-settings.md). */\n AiAgentResolver,\n ChatMessageSubscription,\n /* 「입력 중」 — 저장하지 않는 방의 한 줄. 듣는 사람은 메시지와 같은 방 판정을 지난다. */\n ChatTypingSubscription,\n /* 내가 참여한 모든 세션의 활동 — 창을 닫아 둔 표면이 배지·목록을 갱신할 수 있게. */\n MySessionActivitySubscription,\n /* 사람이 누른 입력 제안을 쓰는 자리 — 행마다 앱의 코드로, 그 사람의 권한으로. */\n EntryProposalResolver\n ]\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import './invite-tools.js';
2
+ export * from './people-keys.js';
3
+ export { peopleReadTarget, PEOPLE_SELECTION } from './people-read.js';
4
+ export { proposeInvite, findPeopleNamed, inviteCategory, MAX_INVITE_CANDIDATES, type InviteCandidate } from './invite-tools.js';
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_INVITE_CANDIDATES = exports.inviteCategory = exports.findPeopleNamed = exports.proposeInvite = exports.PEOPLE_SELECTION = exports.peopleReadTarget = void 0;
4
+ const tslib_1 = require("tslib");
5
+ /*
6
+ * The people tools every conversation carries - the people list (people-read.ts) and the invite card (invite-tools.ts).
7
+ * Registered once, at boot, as the AI 작업판 is.
8
+ */
9
+ const read_tools_js_1 = require("../data-read/read-tools.js");
10
+ const people_read_js_1 = require("./people-read.js");
11
+ require("./invite-tools.js");
12
+ (0, read_tools_js_1.registerReadTarget)((0, people_read_js_1.peopleReadTarget)());
13
+ tslib_1.__exportStar(require("./people-keys.js"), exports);
14
+ var people_read_js_2 = require("./people-read.js");
15
+ Object.defineProperty(exports, "peopleReadTarget", { enumerable: true, get: function () { return people_read_js_2.peopleReadTarget; } });
16
+ Object.defineProperty(exports, "PEOPLE_SELECTION", { enumerable: true, get: function () { return people_read_js_2.PEOPLE_SELECTION; } });
17
+ var invite_tools_js_1 = require("./invite-tools.js");
18
+ Object.defineProperty(exports, "proposeInvite", { enumerable: true, get: function () { return invite_tools_js_1.proposeInvite; } });
19
+ Object.defineProperty(exports, "findPeopleNamed", { enumerable: true, get: function () { return invite_tools_js_1.findPeopleNamed; } });
20
+ Object.defineProperty(exports, "inviteCategory", { enumerable: true, get: function () { return invite_tools_js_1.inviteCategory; } });
21
+ Object.defineProperty(exports, "MAX_INVITE_CANDIDATES", { enumerable: true, get: function () { return invite_tools_js_1.MAX_INVITE_CANDIDATES; } });
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../server/service/people/index.ts"],"names":[],"mappings":";;;;AAAA;;;GAGG;AACH,8DAA+D;AAC/D,qDAAmD;AACnD,6BAA0B;AAE1B,IAAA,kCAAkB,EAAC,IAAA,iCAAgB,GAAE,CAAC,CAAA;AAEtC,2DAAgC;AAChC,mDAAqE;AAA5D,kHAAA,gBAAgB,OAAA;AAAE,kHAAA,gBAAgB,OAAA;AAC3C,qDAA+H;AAAtH,gHAAA,aAAa,OAAA;AAAE,kHAAA,eAAe,OAAA;AAAE,iHAAA,cAAc,OAAA;AAAE,wHAAA,qBAAqB,OAAA","sourcesContent":["/*\n * The people tools every conversation carries - the people list (people-read.ts) and the invite card (invite-tools.ts).\n * Registered once, at boot, as the AI 작업판 is.\n */\nimport { registerReadTarget } from '../data-read/read-tools.js'\nimport { peopleReadTarget } from './people-read.js'\nimport './invite-tools.js'\n\nregisterReadTarget(peopleReadTarget())\n\nexport * from './people-keys.js'\nexport { peopleReadTarget, PEOPLE_SELECTION } from './people-read.js'\nexport { proposeInvite, findPeopleNamed, inviteCategory, MAX_INVITE_CANDIDATES, type InviteCandidate } from './invite-tools.js'\n"]}
@@ -0,0 +1,34 @@
1
+ import { type ToolCategory } from '@things-factory/ai-client-base';
2
+ import type { GraphqlRunner } from '../data-entry/entry-update.js';
3
+ /** At most this many people on one card - a name that matches more is too broad to pick from. */
4
+ export declare const MAX_INVITE_CANDIDATES = 8;
5
+ export interface InviteCandidate {
6
+ userId: string;
7
+ name: string;
8
+ department?: string;
9
+ position?: string;
10
+ }
11
+ /**
12
+ * The people a name means, as the person may see them: the exact name first, then the name as a search term. Only
13
+ * people with an account - an invite seats a user.
14
+ */
15
+ export declare function findPeopleNamed(run: GraphqlRunner, name: string): Promise<{
16
+ people: InviteCandidate[];
17
+ error?: string;
18
+ }>;
19
+ export declare function proposeInvite(args: any, context: any, run?: GraphqlRunner): Promise<{
20
+ rejected: boolean;
21
+ error: string;
22
+ message: string;
23
+ } | {
24
+ people: InviteCandidate[];
25
+ message: string;
26
+ reason?: string;
27
+ proposed: boolean;
28
+ kind: string;
29
+ icon: string;
30
+ label: any;
31
+ rejected?: undefined;
32
+ error?: undefined;
33
+ }>;
34
+ export declare const inviteCategory: ToolCategory;
@@ -0,0 +1,144 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.inviteCategory = exports.MAX_INVITE_CANDIDATES = void 0;
4
+ exports.findPeopleNamed = findPeopleNamed;
5
+ exports.proposeInvite = proposeInvite;
6
+ /*
7
+ * proposeInvite - the model offers a card that brings someone into this conversation (ADR-0073 decision 3).
8
+ *
9
+ * The card is a proposal: the model seats nobody. What an assistant writes must not seat people (mention-invite.ts,
10
+ * rule ①), so the seat is given when a person presses the card - the dock calls `inviteToAISession` with that
11
+ * person's request, and the door asks `maySeat` with their seat. This tool only finds who is meant and says whether
12
+ * this person could press it here.
13
+ *
14
+ * Who is meant is the server's to settle, never the model's memory: the name is looked up in the organization's own
15
+ * list as the person (the read people-read.ts opens), so a user id the model made up is never on a card. One person
16
+ * by that name - the card invites them. Several - the card lists each and the person picks one; the model does not ask.
17
+ */
18
+ const ai_client_base_1 = require("@things-factory/ai-client-base");
19
+ const shell_1 = require("@things-factory/shell");
20
+ const entry_tools_js_1 = require("../data-entry/entry-tools.js");
21
+ const chat_session_js_1 = require("../chat-session/chat-session.js");
22
+ const session_visibility_js_1 = require("../chat-session/session-visibility.js");
23
+ const chat_session_participant_js_1 = require("../chat-session-participant/chat-session-participant.js");
24
+ const participant_lookup_roles_js_1 = require("../chat-session-participant/participant-lookup-roles.js");
25
+ const people_read_js_1 = require("./people-read.js");
26
+ const people_keys_js_1 = require("./people-keys.js");
27
+ /** At most this many people on one card - a name that matches more is too broad to pick from. */
28
+ exports.MAX_INVITE_CANDIDATES = 8;
29
+ const PEOPLE_QUERY = 'query ($filters: [Filter!], $pagination: Pagination, $search: String) ' +
30
+ `{ employees(filters: $filters, pagination: $pagination, search: $search) { items { ${people_read_js_1.PEOPLE_SELECTION} } total } }`;
31
+ const ACTIVE = { name: 'active', operator: 'eq', value: true };
32
+ const candidateOf = (row) => row?.user?.id
33
+ ? {
34
+ userId: String(row.user.id),
35
+ name: String(row.name ?? ''),
36
+ ...(row.department?.name ? { department: String(row.department.name) } : {}),
37
+ ...(row.jobPosition ? { position: String(row.jobPosition) } : {})
38
+ }
39
+ : undefined;
40
+ /**
41
+ * The people a name means, as the person may see them: the exact name first, then the name as a search term. Only
42
+ * people with an account - an invite seats a user.
43
+ */
44
+ async function findPeopleNamed(run, name) {
45
+ const ask = async (variables) => {
46
+ const answer = await run(PEOPLE_QUERY, { pagination: { page: 1, limit: exports.MAX_INVITE_CANDIDATES + 1 }, ...variables });
47
+ if (answer.errors?.length)
48
+ return { error: answer.errors.map(one => one.message).join('; ') };
49
+ return { rows: (answer.data?.employees?.items ?? []) };
50
+ };
51
+ const exact = await ask({ filters: [ACTIVE, { name: 'name', operator: 'eq', value: name }] });
52
+ if ('error' in exact)
53
+ return { people: [], error: exact.error };
54
+ const rows = exact.rows.length ? exact.rows : (await ask({ filters: [ACTIVE], search: name })).rows ?? [];
55
+ return { people: rows.map(candidateOf).filter(Boolean) };
56
+ }
57
+ /** Why this person cannot bring anyone into this room, in their words - or nothing when they can. */
58
+ function seatRefusal(visibility, t) {
59
+ if (visibility === 'private')
60
+ return t('ai-assistant.text.invite-private-refused', { defaultValue: 'a private conversation is yours alone. make it a group to bring people in.' });
61
+ return t('ai-assistant.text.invite-owner-only', { defaultValue: 'only the person who started this group conversation can bring people in.' });
62
+ }
63
+ async function proposeInvite(args, context, run = (0, entry_tools_js_1.runAsCaller)(context)) {
64
+ const t = (key, options) => (typeof context?.t === 'function' ? context.t(key, options) : String(options?.defaultValue ?? key));
65
+ const { domain, user } = context?.state ?? {};
66
+ const name = typeof args?.name === 'string' ? args.name.trim() : '';
67
+ const wanted = typeof args?.userId === 'string' ? args.userId.trim() : '';
68
+ if (!name)
69
+ return { rejected: true, error: 'no-name', message: 'say whom to invite - the name the person used.' };
70
+ const conversationId = context?.conversation?.id;
71
+ const session = conversationId && domain?.id ? await (0, shell_1.getRepository)(chat_session_js_1.ChatSession).findOne({ where: { id: conversationId, domain: { id: domain.id } } }) : undefined;
72
+ if (!session)
73
+ return { rejected: true, error: 'no-conversation', message: 'this conversation is not stored yet, so nobody can be brought into it.' };
74
+ /* Asked before anyone is looked up: the card must be one this person can press here. */
75
+ const seats = await (0, shell_1.getRepository)(chat_session_participant_js_1.ChatSessionParticipant).find({ where: { domain: { id: domain.id }, session: { id: session.id } } });
76
+ const mine = seats.find((seat) => seat.userId === user?.id)?.role;
77
+ if (!(0, session_visibility_js_1.maySeat)(session.visibility, mine)) {
78
+ /* Who reads the conversation is the person's to change, in the conversation list - the model has no tool for it (2026-10-24: it offered 「그룹 대화로 바꿔줘」). */
79
+ return {
80
+ rejected: true,
81
+ error: 'may-not-invite',
82
+ message: `${seatRefusal(session.visibility, t)} Say so in one line - do not offer a card. Who reads this conversation is changed by the person who started it, from the conversation list (⋯); you cannot change it, so never offer to or suggest asking you.`
83
+ };
84
+ }
85
+ const found = await findPeopleNamed(run, name);
86
+ if (found.error)
87
+ return { rejected: true, error: 'people-unreadable', message: `the people list could not be read: ${found.error}` };
88
+ const here = new Set(seats.filter((seat) => (0, participant_lookup_roles_js_1.isRoomRole)(seat.role)).map((seat) => seat.userId));
89
+ const already = found.people.filter(one => here.has(one.userId));
90
+ let people = found.people.filter(one => !here.has(one.userId) && one.userId !== user?.id);
91
+ if (wanted)
92
+ people = people.filter(one => one.userId === wanted);
93
+ if (!people.length) {
94
+ return already.length
95
+ ? { rejected: true, error: 'already-here', message: `${already.map(one => one.name).join(', ')} is already in this conversation.` }
96
+ : { rejected: true, error: 'not-found', message: `no one named "${name}" with an account is in the people list this person may see.` };
97
+ }
98
+ if (people.length > exports.MAX_INVITE_CANDIDATES) {
99
+ return { rejected: true, error: 'too-many', message: `more than ${exports.MAX_INVITE_CANDIDATES} people match "${name}" - ask for the full name or the department.` };
100
+ }
101
+ const one = people.length === 1 ? people[0] : undefined;
102
+ return {
103
+ proposed: true,
104
+ kind: 'invite',
105
+ icon: 'person_add',
106
+ label: one
107
+ ? t('ai-assistant.people.invite-one', { name: one.name, defaultValue: 'Invite {name} to this conversation' })
108
+ : t('ai-assistant.people.invite-pick', { name, count: people.length, defaultValue: '{count} people named {name} - pick whom to invite' }),
109
+ ...(one && (one.department || one.position) ? { reason: [one.department, one.position].filter(Boolean).join(' · ') } : {}),
110
+ people,
111
+ message: one
112
+ ? `the card invites ${one.name}${one.department ? ` (${one.department})` : ''}. The person presses it; they are told when they join. Say that in one line.`
113
+ : `${people.length} people match "${name}"; the card lists each with department and position and the person picks one. Do not ask which - the card does.`
114
+ };
115
+ }
116
+ const spec = {
117
+ kind: 'read',
118
+ name: 'proposeInvite',
119
+ /* It reads people through the organization's list - the same door that list has, so it is offered where that list is. */
120
+ doors: ['Query.employees'],
121
+ description: 'Offer a card that brings someone into this conversation. Give the name the person used; the server finds them in ' +
122
+ "the organization's people list and puts them on the card (several people by that name: the card lists each, the " +
123
+ 'person picks). The person presses the card - nobody joins until then. One call per person.',
124
+ schema: {
125
+ type: 'object',
126
+ properties: {
127
+ name: { type: 'string', description: 'The name of the person to invite, as the person said it.' },
128
+ userId: { type: 'string', description: 'The user id from the people list, when it was read already and the person meant that one.' }
129
+ },
130
+ required: ['name']
131
+ },
132
+ builder: (args, context) => proposeInvite(args, context)
133
+ };
134
+ exports.inviteCategory = {
135
+ name: people_keys_js_1.INVITE_CATEGORY,
136
+ description: 'bring someone into this conversation - a card the person presses',
137
+ guidance: [
138
+ '- When the person asks to invite, add or bring someone into this conversation, call proposeInvite with that name in the same turn. Never send them to a screen to do it.',
139
+ '- To answer who someone is or who works where, read the people list (queryOrganizationEmployee).'
140
+ ].join('\n'),
141
+ specs: [spec]
142
+ };
143
+ (0, ai_client_base_1.registerToolCategory)(exports.inviteCategory);
144
+ //# sourceMappingURL=invite-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invite-tools.js","sourceRoot":"","sources":["../../../server/service/people/invite-tools.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * proposeInvite - the model offers a card that brings someone into this conversation (ADR-0073 decision 3).\n *\n * The card is a proposal: the model seats nobody. What an assistant writes must not seat people (mention-invite.ts,\n * rule ①), so the seat is given when a person presses the card - the dock calls `inviteToAISession` with that\n * person's request, and the door asks `maySeat` with their seat. This tool only finds who is meant and says whether\n * this person could press it here.\n *\n * Who is meant is the server's to settle, never the model's memory: the name is looked up in the organization's own\n * list as the person (the read people-read.ts opens), so a user id the model made up is never on a card. One person\n * by that name - the card invites them. Several - the card lists each and the person picks one; the model does not ask.\n */\nimport { registerToolCategory, type ToolCategory, type ToolSpec } from '@things-factory/ai-client-base'\nimport { getRepository } from '@things-factory/shell'\n\nimport { runAsCaller } from '../data-entry/entry-tools.js'\nimport type { GraphqlRunner } from '../data-entry/entry-update.js'\nimport { ChatSession } from '../chat-session/chat-session.js'\nimport { maySeat } from '../chat-session/session-visibility.js'\nimport { ChatSessionParticipant } from '../chat-session-participant/chat-session-participant.js'\nimport { isRoomRole } from '../chat-session-participant/participant-lookup-roles.js'\nimport { PEOPLE_SELECTION } from './people-read.js'\nimport { INVITE_CATEGORY } from './people-keys.js'\n\n/** At most this many people on one card - a name that matches more is too broad to pick from. */\nexport const MAX_INVITE_CANDIDATES = 8\n\nexport interface InviteCandidate {\n userId: string\n name: string\n department?: string\n position?: string\n}\n\nconst PEOPLE_QUERY =\n 'query ($filters: [Filter!], $pagination: Pagination, $search: String) ' +\n `{ employees(filters: $filters, pagination: $pagination, search: $search) { items { ${PEOPLE_SELECTION} } total } }`\n\nconst ACTIVE = { name: 'active', operator: 'eq', value: true }\n\nconst candidateOf = (row: any): InviteCandidate | undefined =>\n row?.user?.id\n ? {\n userId: String(row.user.id),\n name: String(row.name ?? ''),\n ...(row.department?.name ? { department: String(row.department.name) } : {}),\n ...(row.jobPosition ? { position: String(row.jobPosition) } : {})\n }\n : undefined\n\n/**\n * The people a name means, as the person may see them: the exact name first, then the name as a search term. Only\n * people with an account - an invite seats a user.\n */\nexport async function findPeopleNamed(run: GraphqlRunner, name: string): Promise<{ people: InviteCandidate[]; error?: string }> {\n const ask = async (variables: Record<string, unknown>) => {\n const answer = await run(PEOPLE_QUERY, { pagination: { page: 1, limit: MAX_INVITE_CANDIDATES + 1 }, ...variables })\n if (answer.errors?.length) return { error: answer.errors.map(one => one.message).join('; ') }\n return { rows: (answer.data?.employees?.items ?? []) as any[] }\n }\n const exact = await ask({ filters: [ACTIVE, { name: 'name', operator: 'eq', value: name }] })\n if ('error' in exact) return { people: [], error: exact.error }\n const rows = exact.rows!.length ? exact.rows! : ((await ask({ filters: [ACTIVE], search: name })) as any).rows ?? []\n return { people: rows.map(candidateOf).filter(Boolean) as InviteCandidate[] }\n}\n\n/** Why this person cannot bring anyone into this room, in their words - or nothing when they can. */\nfunction seatRefusal(visibility: string | null | undefined, t: (key: string, options: any) => string): string | undefined {\n if (visibility === 'private')\n return t('ai-assistant.text.invite-private-refused', { defaultValue: 'a private conversation is yours alone. make it a group to bring people in.' })\n return t('ai-assistant.text.invite-owner-only', { defaultValue: 'only the person who started this group conversation can bring people in.' })\n}\n\nexport async function proposeInvite(args: any, context: any, run: GraphqlRunner = runAsCaller(context)) {\n const t = (key: string, options: any) => (typeof context?.t === 'function' ? context.t(key, options) : String(options?.defaultValue ?? key))\n const { domain, user } = context?.state ?? {}\n const name = typeof args?.name === 'string' ? args.name.trim() : ''\n const wanted = typeof args?.userId === 'string' ? args.userId.trim() : ''\n if (!name) return { rejected: true, error: 'no-name', message: 'say whom to invite - the name the person used.' }\n\n const conversationId = context?.conversation?.id\n const session: any = conversationId && domain?.id ? await getRepository(ChatSession).findOne({ where: { id: conversationId, domain: { id: domain.id } } as any }) : undefined\n if (!session) return { rejected: true, error: 'no-conversation', message: 'this conversation is not stored yet, so nobody can be brought into it.' }\n\n /* Asked before anyone is looked up: the card must be one this person can press here. */\n const seats = await getRepository(ChatSessionParticipant).find({ where: { domain: { id: domain.id }, session: { id: session.id } } as any })\n const mine = seats.find((seat: any) => seat.userId === user?.id)?.role\n if (!maySeat(session.visibility, mine)) {\n /* Who reads the conversation is the person's to change, in the conversation list - the model has no tool for it (2026-10-24: it offered 「그룹 대화로 바꿔줘」). */\n return {\n rejected: true,\n error: 'may-not-invite',\n message: `${seatRefusal(session.visibility, t)} Say so in one line - do not offer a card. Who reads this conversation is changed by the person who started it, from the conversation list (⋯); you cannot change it, so never offer to or suggest asking you.`\n }\n }\n\n const found = await findPeopleNamed(run, name)\n if (found.error) return { rejected: true, error: 'people-unreadable', message: `the people list could not be read: ${found.error}` }\n const here = new Set(seats.filter((seat: any) => isRoomRole(seat.role)).map((seat: any) => seat.userId))\n const already = found.people.filter(one => here.has(one.userId))\n let people = found.people.filter(one => !here.has(one.userId) && one.userId !== user?.id)\n if (wanted) people = people.filter(one => one.userId === wanted)\n\n if (!people.length) {\n return already.length\n ? { rejected: true, error: 'already-here', message: `${already.map(one => one.name).join(', ')} is already in this conversation.` }\n : { rejected: true, error: 'not-found', message: `no one named \"${name}\" with an account is in the people list this person may see.` }\n }\n if (people.length > MAX_INVITE_CANDIDATES) {\n return { rejected: true, error: 'too-many', message: `more than ${MAX_INVITE_CANDIDATES} people match \"${name}\" - ask for the full name or the department.` }\n }\n\n const one = people.length === 1 ? people[0] : undefined\n return {\n proposed: true,\n kind: 'invite',\n icon: 'person_add',\n label: one\n ? t('ai-assistant.people.invite-one', { name: one.name, defaultValue: 'Invite {name} to this conversation' })\n : t('ai-assistant.people.invite-pick', { name, count: people.length, defaultValue: '{count} people named {name} - pick whom to invite' }),\n ...(one && (one.department || one.position) ? { reason: [one.department, one.position].filter(Boolean).join(' · ') } : {}),\n people,\n message: one\n ? `the card invites ${one.name}${one.department ? ` (${one.department})` : ''}. The person presses it; they are told when they join. Say that in one line.`\n : `${people.length} people match \"${name}\"; the card lists each with department and position and the person picks one. Do not ask which - the card does.`\n }\n}\n\nconst spec = {\n kind: 'read',\n name: 'proposeInvite',\n /* It reads people through the organization's list - the same door that list has, so it is offered where that list is. */\n doors: ['Query.employees'],\n description:\n 'Offer a card that brings someone into this conversation. Give the name the person used; the server finds them in ' +\n \"the organization's people list and puts them on the card (several people by that name: the card lists each, the \" +\n 'person picks). The person presses the card - nobody joins until then. One call per person.',\n schema: {\n type: 'object',\n properties: {\n name: { type: 'string', description: 'The name of the person to invite, as the person said it.' },\n userId: { type: 'string', description: 'The user id from the people list, when it was read already and the person meant that one.' }\n },\n required: ['name']\n },\n builder: (args: any, context: any) => proposeInvite(args, context)\n} as ToolSpec\n\nexport const inviteCategory: ToolCategory = {\n name: INVITE_CATEGORY,\n description: 'bring someone into this conversation - a card the person presses',\n guidance: [\n '- When the person asks to invite, add or bring someone into this conversation, call proposeInvite with that name in the same turn. Never send them to a screen to do it.',\n '- To answer who someone is or who works where, read the people list (queryOrganizationEmployee).'\n ].join('\\n'),\n specs: [spec]\n}\n\nregisterToolCategory(inviteCategory)\n"]}
@@ -0,0 +1,8 @@
1
+ /** The organization's people as a read target - its `employees` list, read as the person (people-read.ts). */
2
+ export declare const PEOPLE_READ_KEY = "organization.employee";
3
+ /** The category of that read - `data-read:<key>`, as every read target's. */
4
+ export declare const PEOPLE_READ_CATEGORY = "data-read:organization.employee";
5
+ /** The invite card - bring someone into this conversation (invite-tools.ts). */
6
+ export declare const INVITE_CATEGORY = "chat-invite";
7
+ /** Both, in the order a turn puts them in front: find the person, then the card. */
8
+ export declare const PEOPLE_CATEGORIES: string[];
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ /*
3
+ * The names of the people tools - every conversation carries them (mode-categories.ts), so they live apart from the
4
+ * tools themselves and the categories can be named without loading them.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.PEOPLE_CATEGORIES = exports.INVITE_CATEGORY = exports.PEOPLE_READ_CATEGORY = exports.PEOPLE_READ_KEY = void 0;
8
+ /** The organization's people as a read target - its `employees` list, read as the person (people-read.ts). */
9
+ exports.PEOPLE_READ_KEY = 'organization.employee';
10
+ /** The category of that read - `data-read:<key>`, as every read target's. */
11
+ exports.PEOPLE_READ_CATEGORY = `data-read:${exports.PEOPLE_READ_KEY}`;
12
+ /** The invite card - bring someone into this conversation (invite-tools.ts). */
13
+ exports.INVITE_CATEGORY = 'chat-invite';
14
+ /** Both, in the order a turn puts them in front: find the person, then the card. */
15
+ exports.PEOPLE_CATEGORIES = [exports.PEOPLE_READ_CATEGORY, exports.INVITE_CATEGORY];
16
+ //# sourceMappingURL=people-keys.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"people-keys.js","sourceRoot":"","sources":["../../../server/service/people/people-keys.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,8GAA8G;AACjG,QAAA,eAAe,GAAG,uBAAuB,CAAA;AAEtD,6EAA6E;AAChE,QAAA,oBAAoB,GAAG,aAAa,uBAAe,EAAE,CAAA;AAElE,gFAAgF;AACnE,QAAA,eAAe,GAAG,aAAa,CAAA;AAE5C,oFAAoF;AACvE,QAAA,iBAAiB,GAAG,CAAC,4BAAoB,EAAE,uBAAe,CAAC,CAAA","sourcesContent":["/*\n * The names of the people tools - every conversation carries them (mode-categories.ts), so they live apart from the\n * tools themselves and the categories can be named without loading them.\n */\n\n/** The organization's people as a read target - its `employees` list, read as the person (people-read.ts). */\nexport const PEOPLE_READ_KEY = 'organization.employee'\n\n/** The category of that read - `data-read:<key>`, as every read target's. */\nexport const PEOPLE_READ_CATEGORY = `data-read:${PEOPLE_READ_KEY}`\n\n/** The invite card - bring someone into this conversation (invite-tools.ts). */\nexport const INVITE_CATEGORY = 'chat-invite'\n\n/** Both, in the order a turn puts them in front: find the person, then the card. */\nexport const PEOPLE_CATEGORIES = [PEOPLE_READ_CATEGORY, INVITE_CATEGORY]\n"]}
@@ -0,0 +1,4 @@
1
+ import type { ReadTarget } from '../data-read/read-target.js';
2
+ /** The fields read of each person - the answer may carry nothing else. */
3
+ export declare const PEOPLE_SELECTION = "id name alias jobPosition jobResponsibility department { id name } user { id }";
4
+ export declare function peopleReadTarget(): ReadTarget;