Refactored orchestrator for staged file handling, added structured prompt support, adjusted Feishu file handling

This commit is contained in:
whlaoding
2026-03-08 22:38:29 +08:00
parent e2f806edb3
commit 52b8dbb835
30 changed files with 9325 additions and 34 deletions

3
.vscode/launch.json vendored
View File

@@ -6,6 +6,7 @@
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "auto", "mode": "auto",
"preLaunchTask": "Kill Stale LaodingBot Debug Processes",
"program": "${workspaceFolder}/cmd/bot", "program": "${workspaceFolder}/cmd/bot",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"envFile": "${workspaceFolder}/configs/env" "envFile": "${workspaceFolder}/configs/env"
@@ -15,6 +16,7 @@
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "auto", "mode": "auto",
"preLaunchTask": "Kill Stale LaodingBot Debug Processes",
"program": "${workspaceFolder}/cmd/bot", "program": "${workspaceFolder}/cmd/bot",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"envFile": "${workspaceFolder}/configs/env", "envFile": "${workspaceFolder}/configs/env",
@@ -27,6 +29,7 @@
"type": "go", "type": "go",
"request": "launch", "request": "launch",
"mode": "auto", "mode": "auto",
"preLaunchTask": "Kill Stale LaodingBot Debug Processes",
"program": "${workspaceFolder}/cmd/bot", "program": "${workspaceFolder}/cmd/bot",
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"envFile": "${workspaceFolder}/configs/env", "envFile": "${workspaceFolder}/configs/env",

11
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "Kill Stale LaodingBot Debug Processes",
"type": "shell",
"command": "pkill -f '/LaodingBot/cmd/bot/__debug_bin|dlv.*LaodingBot/cmd/bot|dlv dap' || true",
"problemMatcher": []
}
]
}

View File

@@ -5,7 +5,7 @@ Go-based personal Telegram Agent with:
- Telegram polling transport - Telegram polling transport
- OpenAI-compatible LLM client - OpenAI-compatible LLM client
- SQLite conversation memory + simple compression - SQLite conversation memory + simple compression
- Tool registry with built-in `file` and `shell` tools - Tool registry with built-in `file`, `shell`, and `git` tools
- Default-deny security policy via allowlists - Default-deny security policy via allowlists
- Soul markdown loading for bot personality - Soul markdown loading for bot personality
- Skills markdown loading for capability context - Skills markdown loading for capability context
@@ -50,7 +50,7 @@ go run ./cmd/bot
1. Receive message and load recent memory context 1. Receive message and load recent memory context
2. Match relevant skill(s) from `skills/` 2. Match relevant skill(s) from `skills/`
3. If no skill matched, respond via direct LLM 3. If no skill matched, respond via direct LLM
4. If skill matched, run ReAct and call tools (`shell` / `file`) only when needed 4. If skill matched, run ReAct and call tools (`shell` / `file` / `git`) only when needed
5. Return final answer 5. Return final answer
- No `/tool ...` command is required for normal use. - No `/tool ...` command is required for normal use.
@@ -69,6 +69,7 @@ go run ./cmd/bot
- `shell` only allows commands listed in `ALLOWED_COMMANDS`. - `shell` only allows commands listed in `ALLOWED_COMMANDS`.
- `file` only allows paths inside `ALLOWED_DIRS`. - `file` only allows paths inside `ALLOWED_DIRS`.
- `git` only allows common git subcommands and runs inside `WORK_DIR`.
- Working directory for shell is limited by `WORK_DIR`. - Working directory for shell is limited by `WORK_DIR`.
## Next Iteration ## Next Iteration

View File

@@ -177,6 +177,24 @@ func runMessageChannel(ctx context.Context, cfg config.Config, engine *agent.Orc
} }
lg.Infof("starting feishu transport") lg.Infof("starting feishu transport")
return fs.Run(ctx, func(ctx context.Context, msg feishu.IncomingMessage) (string, error) { return fs.Run(ctx, func(ctx context.Context, msg feishu.IncomingMessage) (string, error) {
if msg.MsgType == "file" && len(msg.FileBytes) > 0 {
content := msg.FileBytes
if msg.FilePath != "" {
if b, err := os.ReadFile(msg.FilePath); err == nil && len(b) > 0 {
content = b
} else if lg != nil {
lg.Warnf("read local file failed path=%s err=%v; fallback to in-memory bytes", msg.FilePath, err)
}
}
files := []llm.InputFile{{
FileName: msg.FileName,
MimeType: msg.FileMime,
Content: content,
}}
// Feishu file event and user question are split into separate messages.
// Use empty text so file IDs are cached and consumed by the next text query.
return engine.HandleMessageWithFiles(ctx, msg.ChatID, msg.UserID, "", files)
}
return engine.HandleMessage(ctx, msg.ChatID, msg.UserID, msg.Text) return engine.HandleMessage(ctx, msg.ChatID, msg.UserID, msg.Text)
}) })
default: default:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,250 @@
Sub-Goal 5: Users experience is
enhanced by the provision of Use Cases: 3 Requirements: 8
value-added services
Figure 2 Structure of this document.
1.6 Product Scope and Perspective
The EIP Projects urban platform is an open common architecture which serves for city data
collection, management and distribution. An urban platform is intended to support the widespread
exploitation of city data by humans and machines in the urban environment. Figure 3 illustrates a
holistic high level overview of the urban platform the EIP project intends to deliver.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 6
The reference architecture for urban platforms should:
• Cater for interoperability between urban infrastructures
• Enable replicability of the solutions/platforms city to city
• Scale without technical constraints and excessive cost increase
• Provide open APIs and SDKs
• Enable Real Time capabilities
• Support implementation of functional and technical capabilities
Figure 3. High level overview of the urban platform (currently approved EC DG CNECT).
The current urban platform market is nascent. Many software vendors offer such a platform, though
many requirements and expectations of the stakeholders of city data are not (fully) addressed. As
a result, current urban platforms are often more costly to design and maintain, less reusable and
often not interoperable platform-to-platform, and susceptible to information fragmentation and
overload.
The urban platform which the EIP initiative intends to design takes a step beyond the platforms
currently on the market by ensuring the requirements are fully founded on a co-created and
common set of representative city needs, from which it solicits suitable industry input, and an open
and managed collaboration between industry, cities and communities, and others, in order to take
into account their needs and concerns. To do this, it is necessary to take a technology agnostic
approach to design an open and common reference architecture for urban platforms. This platform
must ensure data is collected and sustained in accordance with well-stablished standards,
managed in a robust manner so that it can handle high level supply and demand of data, and
distributed across different value chains, systems and stakeholders. The ability to handle high level
of city data supply and demand while being user secure and accessible enough for city-wide
exploitation of data is one of many keys to the success of urban platforms. This is central to the
design and implementation of urban platforms.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 7
1.7 The Urban Platform Development Stack
The requirements specification of this document is based on the Urban Platform Development
Stack illustrated in Figure 4. The stack is composed by five domains (represented as layers in the
stack) necessary to fully implement an urban platform software suite as shown in Table 1. Each
domain comprehends a set of requirements necessary to the design of a common and open urban
data service platform. The elicited requirements are used to define a technical architecture which is
simple enough to be comprehensible at least at a high level of abstraction. The platform should be
conceptually decomposable into its major subsystems, the platforms functionality reused by many
services and external applications should be identifiable, and interactions between the platform
and services, data providers and data consumers should be well defined and explicit.
The first layer of the stack “Societal needs” concerns to outcomes we strive for within a portfolio of
city service domains. An urban platform should recognise societal needs and wants as the starting
point for city data service offering. Ultimately, an urban platform aims to provide tailor made and
compelling engaging services for the users. The Services and Business models layers concerns
with delivering data services which carefully targets the needs and expectations of the different
users of the urban platform, and explore use cases and commercial models where data is used to
deliver different forms of value. The city data layer concerns with the mechanisms necessary to
transform urban platforms into a foundation for widespread exploitation of data, including handling
data architectural features, data usability, semantics and quality aspects. The urban platform layer
concerns to the technology foundation to configure, share, and interpret exponentially increasing
volumes city data and services. Finally, the Infrastructure layer concerns with the base level
connectivity that supports the platform to be scalable and reliable in the long run.
STACK OUTPUT
Requirements to deliver new digital services that will address the
Societal Needs societal needs of cities in a positive manner that relates to political
narratives.
Services & Requirements to new profitable business models and the development
Business Models of an increase range of new and engaging services in the smart cities.
City Data Requirements to provide all city data stakeholders ready access and
delivery of all city data that unpins the decision making process in smart
cities.
Urban Platform Requirements to put in place applications together to build a foundation
for the widespread exploitation of data.
Infrastructure Requirements to deliver the backbone infrastructure that will be used to
capture the opportunities of digital technology and data to enable
transformation.
Figure 4. Urban Platform Development Stack.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 8
Table 1. Urban Platform Development Stack
Layer Rationale
Societal Needs - Accessible services and data necessary to solve social problems
and drive innovation;
- Parameters that influence users experience while interacting with
services (e.g. usability, feeling of security and trust);
Services and Business - Tailor-made data services which careful targets the needs of users
Models and businesses;
- New potential and cost-effective beneficial services that could be
rolled out across cities of different sizes;
- Use cases where data is used to deliver different forms of value.
City Data - Data architectural features (e.g. volume, variety, temporal factors
and sensitivity);
- Data licensing, policies and regulations to exploit data to full effect;
- Minimum metadata requirements;
- Data usability and reusability aspects of humans and machines.
Urban Platform - Holistic and interoperable solutions;
- Integrated approaches which ensures that services fit together and
that synergies can be exploited;
- Data management mechanisms to ensure data integrity and
compliance with data protection regulations
- Extension capabilities to accommodate additional functionality at
later stage at a fair and transparent cost.
1.8 User Classes, Characteristics, and User Access
The users of the Urban Platform include end-users, such as the general Public, public and private
organisations; data providers; service providers; and the platform providers who will be
working with the providers of city data and services, and managing the content, defining policies
and regulations of the platform. A crucial feature of an urban platform is the provision of the
various access levels required by the different types of users. Particular uses need different
access levels to some data than the general public. Data publishers will require access to the
Urban Platform in order to ingest, administer, manage, preserve and access their resources. This
will require multiple levels of access to city data and its respective metadata. Table 2 provides a
description of each class of users.
Table 2. Actors
User Class Rationale
Platform - Maintains the ecosystem of data, services and users;
Provider - Defines standards, licenses and regulations and provides terms and conditions
for platform usage and the commercial exploitation of data and services;
- Decides who are allowed to join the value network of data and services
providers;
City Data - Publishes open and proprietary data into the platform;
Publisher - Manages and maintain resources in the platform accordingly to terms and
conditions.
Data - Deploys open and commercial data services into the platform (e.g. data
Services visualisation, data cleansing, data integration tools);
Provider - Manages and maintain resources in the platform accordingly to terms and
conditions.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 9
City Data - Consumes open and proprietary data provided in the platform;
Consumer - Uses open and commercial data services provided in the platform;
- Provides feedback on data and services provision;
1.8.1 End-User Access
City data consumers will need to access and use the city data residing in the Urban Platform. End-
users will be able to search metadata and full text within datasets (when available), and obtain city
data in open formats readily available to both humans and machines such as CSV, XML, JSON.
Some end-users may require different access rights to city data. The 2 major end-user groups that
have been identified are:
• Open data users, including both national and international users (humans and machines).
Open access to some city data may be restricted by licensing terms (e.g. commercial data),
embargo periods, copyright, etc.
• Private data users, which need to use the Urban Platform to obtain commercial city data. Data
access is available via data subscriptions or when purchase requirements and licenses are
waived by the data provider.
1.8.2 City Data Publisher Access
A broad data provider level access is needed for stakeholders (humans and machines) working
with the urban platform and their respective data in it. Basically, data publishers will carry out the
following activities:
• Data publication access, available to publishers adding new data and metadata, checking the
quality of datasets, manipulating data, performing format conversions, defining data-access
level, tariff for consumption when applicable, and licences.
• Data maintenance access, for publishers reviewing or editing appropriate data and metadata in
the urban platform. Data publishers can view data and add to or edit metadata without
changing the data itself. They should be provided with access to feedback from users to
investigate problem in their resources (e.g. missing data, inconsistent metadata), and statistical
information about how their resources are used by users.
1.8.3 Data Services Provider Access
This is the second most restrictive access level providing rights to deploy services in the platform.
Basically, data service providers will carry out the following activities:
• Data services deployment access, available to service providers adding new mechanisms or
integrating new applications, testing and validating integration, defining data-access level and
tariff for service usage.
• Data services maintenance access, for services providers reviewing, extending or editing
applications in the urban platform. Data services providers can view their services deployed
and add to or edit access level and tariff without having to deploy the services again. They
should be provided with access to feedback from users to investigate problem in their services
(e.g. bugs, scalability issues), and statistical information about how their services are used by
users.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 10
1.8.4 Platform Provider Access
This is the most restrictive access level providing ultimate rights to the system and is required for
its management, development, and assigning appropriate rights to data and services providers.
Policies and regulations, license agreements are also defined by the provider of the urban
platform. Platform providers should be provided with the means to follow up on civic engagement
(e.g. feedback, request for city data) and on the provision of city data and services.
1.9 User Documentation
• City Data Consumers: Provide license terms and conditions associated to consuming
data and services provided in the platform, documentation of APIs and guide to
discover city data in the platform.
• City Data Providers: Provide data publication documentation describing the minimum
metadata requirements, formats accepted, step-by-step guide to publish accurate city
data.
• Data Service Providers: Disclosure technical and architecture blueprint details in
order share and outsource expertise, and partnerships, and integrate supporting
partners solutions into the platform itself.
1.10 Design and Implementation Constraints
1.10.1 Design Constraints
• Lack of standards agreement for metadata representation.

View File

@@ -0,0 +1,600 @@
• City data found in existing data catalogues may require special consideration concerning the
type of formats and datasets that must be stored within the platform.
• Requirements mismatch due to increased number of stakeholders involved in the design
1.10.2 Implementation Constraints
• Evaluation and testing of software options is expected to occur prior to selection and
implementation of a production urban platform.
• Budget costs are unknown until evaluation of software options is completed.
1.11 Assumptions, Alignment with other Action Clusters and Policies
1.11.1 Assumptions
The assumptions in Table 3 have been identified by the Demand Side Engagement Stream as
relevant to this Requirements Specification.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 11
Table 3. Assumptions
# ASSUMPTION
1 The providers of city data and services will be responsible to maintain their resources in the platform.
2 All city data must meet the minimum metadata requirements and use the standards adopted by the platform.
3 The platform shall consider open Source as an optional commercial model, with open standards as a principle
4 The system design and architecture should minimize fragmentation of city data in the urban platform.
5 To the extent possible, automation should be used for the extraction of descriptive and technical metadata.
6 The platform must be designed in a way it accommodates additional functionality at later stage at a fair and transparent cost.
The platform must be a modular based architecture which relies on stable and well-defined open interfaces to ensure
7
interoperability between the platform, services and the applications provided by service providers.
The platform will offer open and well-documented APIs and clear service descriptions and contracts that is offered for reuse by
8 another party to foster open innovation in the city, which means that developers and interested individuals openly utilize the
resources provided.
9 Adopt open and published European and International standards where possible.
The platform must be flexible enough to accommodate different local, National and International data protection, licensing and
10
commercialization regulations.
11 Platform providers will monitor emerging technologies in order to maintain and improve the architecture.
12 Platform providers will monitor emerging information standards, including metadata standards and data interface standards.
13 Platform providers will monitor new commercial models for city data exploitation
1.11.2 Alignment with Citizens Focus Action Cluster
This specification document is aligned with the principles defined in the Citizen Focus5 Action
Cluster of the European Innovation Partnership on Smart Cities and Communities. Citizen Focus is
about “working together with citizens to realize public interests at the intersection of ICT, mobility
and energy in an urban environment”. We recognize citizens as owners of and participants in
the creation and delivery of city data and digital services, and we specify requirements to deliver
new digital services that will address the societal needs of cities in a positive manner that relates to
political narratives. Societal needs and wants are considered the starting point for city data service
offering by the urban platform. The requirements in this document were elicited considering
• Human behaviour and needs as important as technology;
• The services and data that solve social problems and drive innovation;
• The mechanisms that make data and services more accessible to users;
• The factors that influences users experience while interacting with services provided (e.g.
usability, feeling of security and trust);
5
https://eu-smartcities.eu/node/1333
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 12
1.11.3 Policies to be developed
The following policies have been identified by the Demand Side Engagement Stream as relevant to
this Requirements Specification.
• Data formatting and Metadata Schemes: Urban platforms will require more expansive, robust
and useful data encoding and conversion that what is available in existing data catalogues.
Data preservation policies should be developed to allow data to be stored in formats that can
be migrated, associated with metadata and ontologies to become both humans and machines
readable and understandable, ongoing monitoring for data obsolescence, and migrating data to
systems environments as needed to ensure their continued availability. Current Metadata
schemes (e.g. open data, sensory data ontologies) should be reviewed to see if it meets
current needs for city data management. It is possible that the needs of the urban platform
designed here may require new or additional schemas.
• Data commercialisation: The commercial exploitation of city data and their funding models
are unexplored concepts that we are committed to address. There is an urgent need to define
license agreements and fair commercial and subscription models to allow interoperable open
and proprietary data to co-exist in the platform.
• Data publication and services deployment: Policy development will be needed regarding
ingesting data and deploying data services into the platform, including which users/machines
will be authorized to submit data for publication, the minimum requirements for data submitted
by open and proprietary data publishers, and the removal of resources and services from the
platform.
2. Urban Platform Value Proposition, Use Cases and
Functional Requirements
2.1 From Value Proposition to Platform Specifications
This document uses goal-oriented modelling for eliciting, elaborating, structuring, specifying,
documenting, and modifying requirements. Goals represent the objectives which the urban
platform should achieve through cooperation of actors in the intended system and in the
environment. They capture, at different levels of abstraction, the various objectives the urban
platform under design should achieve. Through goals modelling we consider how the value
proposition and intended solutions connects across the stack, how the urban platform meets city
goals, why the system and its functionality are needed, and how the stakeholders interests may be
addressed.
In our specification, we present the overall goal (the value proposition) that the urban platform
should aim to achieve in order to be considered as a viable final product, and a set of sub-goals
(intended solutions) it should maintain in the long run so that the overall goal can be unceasingly
achieved. By using this approach, the low-level technical requirements can be traced back to high-
level strategic objectives of the urban platform. The formal notations used in this document are:
Achieve [“Name of Overall Goal”] and Maintain [“Name of Sub-Goal”]. The requirements of the
Urban Platform are noted for each of the sub-goals, and are presented as a series of statements
regarding the capabilities needed in to achieve the overall goal of the Urban Platform.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 13
2.2 Overall Goal: “City data is exploited to its full potential”
An urban platform is an organization of people and systems, which has accepted the responsibility
to preserve city data and make it available for all the stakeholders of smart cities. Ultimately, an
urban platform is a foundation for the full exploitation of city data. Hence, the major goal an Urban
Platform must achieve is “city data is exploited to its full potential”. To achieve this high level goal,
the urban platform must maintain in the long run the five sub-goals illustrated in Figure 3.
Each one of the defined sub-goals co-enables the achievement of the specified high-level (overall)
goal of the urban platform. The sub-goals include the ingestion of city data, metadata generation,
data management, data storage, access, preservation, and administration, provision of engaging
services in the smart cities. These sub-goals are discussed in details in the following sections.
Achieve [City data is exploited How we achieve the platform overall goal?
Why do we need the sub-goals?
to its full effect]
Goal
Maintain [User s experience is
Maintain [City data is provided
enhanced by the provision of
in a harmonised way]
S ub-Goal 1 S ub-Goal 5 value-added services]
co-ena bles
Maintain [Resources are managed in Maintain [City data is offered
a safe and intelligent manner] in an accessible manner]
S ub-Goal 2 S ub-Goal 4
Maintain [City data is orchestrated
in a market place]
S ub-Goal 3
Figure 3. Platform High-Level Goal and its respective sub-goals.
2.2.1 Urban Platform Boundary
The use case diagram illustrated in Figure 4 identifies the boundaries between the actors (either
automated or human) and the urban platform. We have arrived at the urban platform boundary by
inspecting each business use case and determining, in conjunction with the stakeholders needs,
which part of the business use case should be implemented and what part should be done by an
outsourced product (e.g. Billing System) using the framework 4.
This task is technology agnostic and takes into account the abilities of the users/actors, the
constraints, the goals of the urban platform. Table 4 maps out the use cases with their respective
sub-goals and actors.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 14
Manage Services
S ub-Goal 5
Data Service
Publish City Data
Provider
S ub-Goal 1
<<include>> Deploy Data Services
rules
S ub-Goal 5
Authenticate in the
Manage Resources <<include>>
Platform Platform
S ub-Goal 1 Provider Database
<<include>> Manage Infrastructure System
S ub-Goal 2
Utlise Data Services
City Data <<include>>
Publisher S ub-Goal 5
Store City Data Management
<<include>>
S ub-Goal 2
Systems Services
System
<<include>>
City Data
Consumer
QoS Monitoring
Transmit Data
System
Register in the Platform S ub-Goal 2
<<include>>
rules
<<extend>>
rules
Platform
Provider
rules
Commercialise Data
Consume City Data
Services City Data
S ub-Goal 3 S ub-Goal 4
Consumer
<<extend>>
Commercialise
City Data Discover City Data
S ub-Goal 3
S ub-Goal 4
Billing
Management
System
Authenticate in the Register in the
Platform Platform
Authenticate Authenticate
Register Consumers Register Publishers
Consumers Publishers
Figure 4. Simplistic overview of the use cases identified in the early stages of the platform design.
Table 4. Use Cases Mapping with Sub-Goals and Actors
Sub-Goals Use Cases ID Specialised Use Cases Actors
HIGH-LEVEL GOAL: City data is exploited to its
Publish City Data UC1 User publishes city data via data APIs
City Data Publisher
1. City data is Register as a publisher
UC2 User manually uploads datasets
provided in a in the Platform
harmonised way
full effect
User manages resources
Manage Resources UC3 City Data Publisher
User tracks resources usage
Store City Data UC4
2. City data is
managed in a safe Transmit Data UC5 - Management Systems
and intelligent
manner
Manage Infrastructure UC6
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 15
City Data Publisher
Set commercial city data
Platform Provider
Subscribe to proprietary data City Data Consumer
Commercialise City
UC7
Data
Manage commercial data City Data Publisher
3. City data is Manage data subscription City Data Consumer
orchestrated in a
Data Services Provider
market place Set commercial data services
Platform Provider
Subscribe to commercial services Data Services Consumer
Commercialise Data
UC8
Services
Manage commercial services Data Services Provider
Manage services subscription Data Services Consumer
UC9
Register in the Platform City Data Consumer
-
4. City data is Discover City Data City Data Consumer
UC10
offered in an
User consumes city data via data
accessible manner
APIs
Consume City Data UC11 City Data Consumer
User downloads datasets
5. Users Data Services Provider
Deploy Data Services UC12
experience is Platform Provider
enhanced by the
Manage Services UC13 - Data Services Provider
provision of value-
added services
Utilise Data Services UC14 City Data Consumer
2.3 SUB-GOAL 1: City data is collected in an intelligent manner
Description: The urban platform enables the owners of city data to easily publish both historic and
data streams in the platform, as well as their associated metadata.
Rationale: This sub-goal is maintained by the services and functions to accept the publication of
city data from data providers (of both open and proprietary data) and prepare the contents for
storage and management within the urban platform. Functions include receiving data, performing
quality assurance on data, verifying data formatting and document standards, associating meta-
data information, and coordinating updates to databases and resources management.
Achieve [City data is exploited
to its full effect]
Goal
co-ena bles
How we achieve the platform overall goal?
Maintain [City data is provided in
a harmonised manner]
S ub-Goal 1
What actions can maintain the sub-goal?
Achieve [Register Publisher] Achieve [Publish City Data] Achieve [Manage Resources]
UC1 UC2 UC3
Figure 5. Sub-Goal 1 “City data is collected in an intelligent manner” refinement.
Drivers: Ensure data is published in an easy and uniform way.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 16
Actions: For Sub-Goal 1 to be maintained in the long-run it requires the efficient realisation of use
cases: “Publish City Data” and “Manage Resources”, as shown in Figure 5.
2.3.1 Use Case: Register Publisher
ID: UC1
Refines: SUB-GOAL 1: City data is collected in an intelligent manner
Pre-condition: Data Publisher is not logged in the system
Actors: Data Publishers
Rationale: Data Publishers can register in the platform and request approval to submit city data.
They provide valid registration details (to be defined) and wait for registration confirmation.
Platform Providers may authorise or not data publishers to offer both open and proprietary city data
in the platform. Data submission agreement is a formal agreement between the Data Provider and
the Urban Platform defining the terms of the content, standards, metadata creation, and license
agreement. The Urban Platform will proactively work with Data Providers to agree on the content,
quality and format of city data. Agreements between Platform and Data Providers may be
renegotiated on a periodic or ad-hoc basis.
Refines into requirements: FREQ.1 to FREQ.5.
Use Case Basic Stimulus and Responses
1. The platform prompts the user for a username and password or
register new account.
2. The user selects registration option.
3. The platform prompts user for publisher registration information (e.g.
username, password, organisation)
4. The user enters in their information.
UC1. Register 5. Platform verifies information and creates account.
Publisher o If non-valid information, platform shows error message and
returns to step 1.
6. Platform provider is requested to approve the account
o Platform acknowledges registration has been successful
o If non approved, platform shows error message and returns to
step 1.
7. End of registration
2.3.2 Use Case: Publish City Data
ID: UC2
Refines: SUB-GOAL 1 - City data is collected in an intelligent manner
Pre-condition: User is authenticated in the platform
Actors: City data publisher
Rationale: The Publish City Data function provides the appropriate mechanisms to receive city data from
authorized data providers. Data may be manually uploaded or submitted via APIs. In general, data providers
with whom the Urban Platform negotiates submission agreements are the providers of proprietary city data
(those producing published material, i.e. publishers) and open data, and they can be either humans or
machines. The providers of the Urban Platform will provide data providers with specifications on the content,
quality and format of data, and publication terms and conditions.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 17
The Publish City Data function may represent a legal transfer of custody for the data in the urban platform,
and may require that special access controls be placed on the contents. This function provides a
confirmation of receipt of data publication to the Producer, which may include a request to resubmit data in
the case of errors resulting from the submission.
Once data has arrived, it must undergo several reviews, including virus checking, format compliance,
metadata minimum requirement agreement, quality and anticipated content and data formatting. The
platform must include the ability to record all actions and decisions made concerning the publication of city
data. The reasons for publication failure (e.g. missing metadata information, non-valid dataset) will be
provided back to the city data publisher. In some cases, the provider can then resubmit corrected data and
metadata information, while in other instances data publication refusal criteria should prevent the publisher
from submitting the same dataset at a later time period (e.g. in cases of suspicious datasets copyrights
violation, viruses). When data is successfully submitted (either via APIs or manual upload), it will be
processed/prepared for storage into the platforms database.
Specialised Use Cases: The Use Case Publish City Data data is distinguished into two
specialised Use Cases: “User publishes city data via data APIs (UC2.1)” and “User manually
uploads datasets (UC2.2)”.
Subordinated Use Cases: “Store City Data (UC4)”
Refines into requirements: FREQ 6 to FREQ.26.
Specialised Use Cases Basic Stimulus and Responses
1. Platform provides user with an interface for static data
publication
2. User selects datasets to be uploaded
3. User provides metadata associated with the data (license,
provenance, ownership, semantics) in accordance with defined
standards
UC2.1. User manually 4. User requests data publication
uploads datasets 5. Platform quickly process users request for data publication
6. Platform validates data submitted
o If valid data, platform acknowledges data publication has
been successful
o If non-valid data, platform shows error message and returns
to step 1.
7. End of data publication
1. Platform provides user with an interface for real-time data
publication
2. User input data API information
3. User provides metadata associated with the data (license,
provenance, ownership, semantics) in accordance with defined
standards
UC2.2. User publishes 4. User confirm information and request data publication
city data via data APIs 5. Platform quickly process users request for data publication
6. Platform validates data submitted
o If valid data, platform acknowledges data publication has
been successful
o If non-valid data, platform shows error message and returns
to step 1
End of data publication
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 18
2.3.3 Use Case: Manage Resources
ID: UC3
Refines: GOAL 1: City data is collected in an intelligent manner
Pre-condition: User successfully authenticates in the platform
Actors: City data publisher
Rationale: Manage resources provides the services and functions for updating, maintaining and
accessing both data and metadata, as well as tracking the usage of resources by users. Ideally
the owners of the resources should be the only authorised user to manage resources, and other
authorised users can track the usage of the resources in the platform. The platform must provide a
database update response indicating the status of the update, avoid update errors to be
propagated in the platform, and should keep an audit trail of all actions to enable rollback. Data
usage tracking includes performing queries on the data management data to generate result sets,
and producing reports from these result sets.
Specialised Use Cases: The Use Case Manage Resources data is distinguished into two
specialised Use Cases: “User manages resources (UC3.1)” and “User tracks resources usage
(UC3.2)”.
Subordinated Use Cases: “Transmit Data (UC5)”
Refines into requirements: FREQ.27 to FREQ.25.
Specialised Use Cases Basic Interactions and Responses
1. Platform provides user with an interface for resources
management (e.g. data and metadata, data usage)
2. User chooses to edit or delete data
3. If edit, user revise metadata associated with the data (license,
provenance, ownership, access-control, semantics);
UC3.1. User manages 4. If delete, user selects dataset(s) to be removed
resources 5. User confirms action
6. Platform quickly process users request
7. Platform confirms execution of request
o If valid request, platform acknowledges request has been
processed successfully
o If non-valid request, platform returns to step 1.
8. End of resources management
1. Platform provides user with an interface for resources
management (e.g. data and metadata, data usage)
2. User chooses to visualise usage information of a dataset
UC3.2. User tracks 3. Platform quickly process users request for data usage
resources usage information
4. Platform provides user with statistical information about data
usage and data users anonymised information
5. End of data usage tracking.
2.3.4 Functional Requirements
Req. ID UC. ID Description Priority Domain
Societal Needs,
FREQ.1 UC1 Allow data publishers to register to submit data for publication Must
Platform
Tracks data publication agreements between Data and Platform Business Needs,
FREQ.2 UC1 Must
Providers Platform
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 19
Store terms of agreements, and use them to monitor/review/process
FREQ.3 UC1 Must City Data, Platform
data submissions.
Able to add and edit terms of agreement, based on access of level of Business Needs,
FREQ.4 UC1 Must
user. Platform
FREQ.5 UC1 Data publications are managed and monitored Must City Data, Platform
Allow authenticated users from across different organisations to City Data, Platform,
FREQ.6 UC2 Must
publish city data Business Needs
Provide authorization mechanisms for users and sensors to publish
FREQ.7 UC2 Must City Data, Platform
city data
City Data, Platform,
FREQ.9 UC2 Provide mechanisms for static data publication Must
Business Needs
City Data, Platform,
FREQ.10 UC2 Provide mechanisms for real-time data publication Must
Business Needs
FREQ.11 UC2 Enable the publication of metadata Must City Data, Platform
FREQ.12 UC2 Maintain temporal information about the data Must City Data, Platform
FREQ.13 UC2 Support sensory data collection Must City Data, Platform
FREQ.14 UC2 Accepts content in numerous file types/formats Must City Data, Platform
Prompts a request for resubmission to the data provider if an error of

View File

@@ -0,0 +1,600 @@
harmonised way
full effect
User manages resources
Manage Resources UC3 City Data Publisher
User tracks resources usage
Store City Data UC4
2. City data is
managed in a safe Transmit Data UC5 - Management Systems
and intelligent
manner
Manage Infrastructure UC6
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 15
City Data Publisher
Set commercial city data
Platform Provider
Subscribe to proprietary data City Data Consumer
Commercialise City
UC7
Data
Manage commercial data City Data Publisher
3. City data is Manage data subscription City Data Consumer
orchestrated in a
Data Services Provider
market place Set commercial data services
Platform Provider
Subscribe to commercial services Data Services Consumer
Commercialise Data
UC8
Services
Manage commercial services Data Services Provider
Manage services subscription Data Services Consumer
UC9
Register in the Platform City Data Consumer
-
4. City data is Discover City Data City Data Consumer
UC10
offered in an
User consumes city data via data
accessible manner
APIs
Consume City Data UC11 City Data Consumer
User downloads datasets
5. Users Data Services Provider
Deploy Data Services UC12
experience is Platform Provider
enhanced by the
Manage Services UC13 - Data Services Provider
provision of value-
added services
Utilise Data Services UC14 City Data Consumer
2.3 SUB-GOAL 1: City data is collected in an intelligent manner
Description: The urban platform enables the owners of city data to easily publish both historic and
data streams in the platform, as well as their associated metadata.
Rationale: This sub-goal is maintained by the services and functions to accept the publication of
city data from data providers (of both open and proprietary data) and prepare the contents for
storage and management within the urban platform. Functions include receiving data, performing
quality assurance on data, verifying data formatting and document standards, associating meta-
data information, and coordinating updates to databases and resources management.
Achieve [City data is exploited
to its full effect]
Goal
co-ena bles
How we achieve the platform overall goal?
Maintain [City data is provided in
a harmonised manner]
S ub-Goal 1
What actions can maintain the sub-goal?
Achieve [Register Publisher] Achieve [Publish City Data] Achieve [Manage Resources]
UC1 UC2 UC3
Figure 5. Sub-Goal 1 “City data is collected in an intelligent manner” refinement.
Drivers: Ensure data is published in an easy and uniform way.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 16
Actions: For Sub-Goal 1 to be maintained in the long-run it requires the efficient realisation of use
cases: “Publish City Data” and “Manage Resources”, as shown in Figure 5.
2.3.1 Use Case: Register Publisher
ID: UC1
Refines: SUB-GOAL 1: City data is collected in an intelligent manner
Pre-condition: Data Publisher is not logged in the system
Actors: Data Publishers
Rationale: Data Publishers can register in the platform and request approval to submit city data.
They provide valid registration details (to be defined) and wait for registration confirmation.
Platform Providers may authorise or not data publishers to offer both open and proprietary city data
in the platform. Data submission agreement is a formal agreement between the Data Provider and
the Urban Platform defining the terms of the content, standards, metadata creation, and license
agreement. The Urban Platform will proactively work with Data Providers to agree on the content,
quality and format of city data. Agreements between Platform and Data Providers may be
renegotiated on a periodic or ad-hoc basis.
Refines into requirements: FREQ.1 to FREQ.5.
Use Case Basic Stimulus and Responses
1. The platform prompts the user for a username and password or
register new account.
2. The user selects registration option.
3. The platform prompts user for publisher registration information (e.g.
username, password, organisation)
4. The user enters in their information.
UC1. Register 5. Platform verifies information and creates account.
Publisher o If non-valid information, platform shows error message and
returns to step 1.
6. Platform provider is requested to approve the account
o Platform acknowledges registration has been successful
o If non approved, platform shows error message and returns to
step 1.
7. End of registration
2.3.2 Use Case: Publish City Data
ID: UC2
Refines: SUB-GOAL 1 - City data is collected in an intelligent manner
Pre-condition: User is authenticated in the platform
Actors: City data publisher
Rationale: The Publish City Data function provides the appropriate mechanisms to receive city data from
authorized data providers. Data may be manually uploaded or submitted via APIs. In general, data providers
with whom the Urban Platform negotiates submission agreements are the providers of proprietary city data
(those producing published material, i.e. publishers) and open data, and they can be either humans or
machines. The providers of the Urban Platform will provide data providers with specifications on the content,
quality and format of data, and publication terms and conditions.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 17
The Publish City Data function may represent a legal transfer of custody for the data in the urban platform,
and may require that special access controls be placed on the contents. This function provides a
confirmation of receipt of data publication to the Producer, which may include a request to resubmit data in
the case of errors resulting from the submission.
Once data has arrived, it must undergo several reviews, including virus checking, format compliance,
metadata minimum requirement agreement, quality and anticipated content and data formatting. The
platform must include the ability to record all actions and decisions made concerning the publication of city
data. The reasons for publication failure (e.g. missing metadata information, non-valid dataset) will be
provided back to the city data publisher. In some cases, the provider can then resubmit corrected data and
metadata information, while in other instances data publication refusal criteria should prevent the publisher
from submitting the same dataset at a later time period (e.g. in cases of suspicious datasets copyrights
violation, viruses). When data is successfully submitted (either via APIs or manual upload), it will be
processed/prepared for storage into the platforms database.
Specialised Use Cases: The Use Case Publish City Data data is distinguished into two
specialised Use Cases: “User publishes city data via data APIs (UC2.1)” and “User manually
uploads datasets (UC2.2)”.
Subordinated Use Cases: “Store City Data (UC4)”
Refines into requirements: FREQ 6 to FREQ.26.
Specialised Use Cases Basic Stimulus and Responses
1. Platform provides user with an interface for static data
publication
2. User selects datasets to be uploaded
3. User provides metadata associated with the data (license,
provenance, ownership, semantics) in accordance with defined
standards
UC2.1. User manually 4. User requests data publication
uploads datasets 5. Platform quickly process users request for data publication
6. Platform validates data submitted
o If valid data, platform acknowledges data publication has
been successful
o If non-valid data, platform shows error message and returns
to step 1.
7. End of data publication
1. Platform provides user with an interface for real-time data
publication
2. User input data API information
3. User provides metadata associated with the data (license,
provenance, ownership, semantics) in accordance with defined
standards
UC2.2. User publishes 4. User confirm information and request data publication
city data via data APIs 5. Platform quickly process users request for data publication
6. Platform validates data submitted
o If valid data, platform acknowledges data publication has
been successful
o If non-valid data, platform shows error message and returns
to step 1
End of data publication
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 18
2.3.3 Use Case: Manage Resources
ID: UC3
Refines: GOAL 1: City data is collected in an intelligent manner
Pre-condition: User successfully authenticates in the platform
Actors: City data publisher
Rationale: Manage resources provides the services and functions for updating, maintaining and
accessing both data and metadata, as well as tracking the usage of resources by users. Ideally
the owners of the resources should be the only authorised user to manage resources, and other
authorised users can track the usage of the resources in the platform. The platform must provide a
database update response indicating the status of the update, avoid update errors to be
propagated in the platform, and should keep an audit trail of all actions to enable rollback. Data
usage tracking includes performing queries on the data management data to generate result sets,
and producing reports from these result sets.
Specialised Use Cases: The Use Case Manage Resources data is distinguished into two
specialised Use Cases: “User manages resources (UC3.1)” and “User tracks resources usage
(UC3.2)”.
Subordinated Use Cases: “Transmit Data (UC5)”
Refines into requirements: FREQ.27 to FREQ.25.
Specialised Use Cases Basic Interactions and Responses
1. Platform provides user with an interface for resources
management (e.g. data and metadata, data usage)
2. User chooses to edit or delete data
3. If edit, user revise metadata associated with the data (license,
provenance, ownership, access-control, semantics);
UC3.1. User manages 4. If delete, user selects dataset(s) to be removed
resources 5. User confirms action
6. Platform quickly process users request
7. Platform confirms execution of request
o If valid request, platform acknowledges request has been
processed successfully
o If non-valid request, platform returns to step 1.
8. End of resources management
1. Platform provides user with an interface for resources
management (e.g. data and metadata, data usage)
2. User chooses to visualise usage information of a dataset
UC3.2. User tracks 3. Platform quickly process users request for data usage
resources usage information
4. Platform provides user with statistical information about data
usage and data users anonymised information
5. End of data usage tracking.
2.3.4 Functional Requirements
Req. ID UC. ID Description Priority Domain
Societal Needs,
FREQ.1 UC1 Allow data publishers to register to submit data for publication Must
Platform
Tracks data publication agreements between Data and Platform Business Needs,
FREQ.2 UC1 Must
Providers Platform
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 19
Store terms of agreements, and use them to monitor/review/process
FREQ.3 UC1 Must City Data, Platform
data submissions.
Able to add and edit terms of agreement, based on access of level of Business Needs,
FREQ.4 UC1 Must
user. Platform
FREQ.5 UC1 Data publications are managed and monitored Must City Data, Platform
Allow authenticated users from across different organisations to City Data, Platform,
FREQ.6 UC2 Must
publish city data Business Needs
Provide authorization mechanisms for users and sensors to publish
FREQ.7 UC2 Must City Data, Platform
city data
City Data, Platform,
FREQ.9 UC2 Provide mechanisms for static data publication Must
Business Needs
City Data, Platform,
FREQ.10 UC2 Provide mechanisms for real-time data publication Must
Business Needs
FREQ.11 UC2 Enable the publication of metadata Must City Data, Platform
FREQ.12 UC2 Maintain temporal information about the data Must City Data, Platform
FREQ.13 UC2 Support sensory data collection Must City Data, Platform
FREQ.14 UC2 Accepts content in numerous file types/formats Must City Data, Platform
Prompts a request for resubmission to the data provider if an error of
FREQ.15 UC2 Must City Data, Platform
data transmission or receipt occurs
FREQ.16 UC2 Enable the semantic description of connected devices Must City Data, Platform
FREQ.17 UC2 Gather data from authenticated and authorized devices Must City Data, Platform
FREQ.18 UC2 Validates automatically the successful transfer of the data Must City Data, Platform
FREQ.19 UC2 Performs virus checking on data Must City Data, Platform
Verifies the validity of the submission based on submitter, expected
FREQ.20 UC2 Must City Data, Platform
format, data quality, and completeness
Platform should have built-in checks on the incoming metadata. Data
FREQ.21 UC2 not containing the minimally defined set of attributes should be Must City Data, Platform
returned to the publisher for metadata enhancement.
System should have a user-friendly method of mapping non-standard
FREQ.22 UC2 Should City Data, Platform
metadata elements into approved standard elements.
Once ingested, metadata should be stored in a single common format.
FREQ.23 UC2 This format should be one that ensures against data loss, and allows a Must City Data, Platform
variety of access/distribution options
Data in the repository shall have sufficient technical metadata to
FREQ.24 UC2 assure functionality (e.g. viewing and display) to ensure accessibility Must City Data, Platform
and reusability.
Allows publishers to display and perform manual/visual quality control Business Needs, City
FREQ.25 UC2 Could
assurance via a user-friendly GUI Data, Platform
Business Needs, City
FREQ.26 UC2 Any errors shall prompt a request for resubmission of data Should
Data, Platform
FREQ.27 UC3 Enable data providers to manage their resources Must Business Needs
A minimal set of identifying information/metadata concerning data Business Needs,
FREQ.28 UC3 Must
publication submission must be recorded Platform
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 20
Stores and tracks versions of data. Links /connections between
FREQ.29 UC3 Must City Data, Platform
versions are created and maintained
Give service and data providers access to anonymized data of the Business Needs
FREQ.30 UC3 Should
subscribers of their data or services
City Data, Platform,
FREQ.31 UC3 Enable data providers to maintain and repair data and metadata Should
Business Needs
Tracks data publication agreements between Data and Platform Business Needs,
FREQ.32 UC3 Must
Providers Platform
Store terms of agreements, and use them to monitor/review/process
FREQ.33 UC3 Must City Data, Platform
data submissions.
Able to add and edit terms of agreement, based on access of level of Business Needs,
FREQ.34 UC3 Must
user. Platform
FREQ.35 UC3 Submission volumes and schedules are managed and monitored Must City Data, Platform
2.4 SUB-GOAL 2: City data is managed in a safe and intelligent manner
Rationale: The urban platform enables users to publish, consume and commercialise data, as well
as deploy and manage services all in a secure and privacy protected manner.
Achieve [City data is exploited
to its full effect]
Goal
co-ena bles
Maintain [Resources are managed in a
safe and intelligent manner]
S ub-Goal 1
Achieve [Store Data] Achieve [Transmit Data] Achieve [Manage Infrastructure]
UC4 UC5 UC6
Figure 6. Sub-Goal 2 “City data is managed in a safe and intelligent manner” refinement.
Drivers: Ensure data is secured and the identity of users are preserved
Actions: For Sub-Goal 2 to be maintained in the long-run it requires the efficient realisation of use
cases: “Store City Data” and “Retrieve and Transmit City Data”, as shown in Figure 6.
2.4.1 Use Case: Store City Data
ID: UC4
Refines: SUB-GOAL 2: City data is managed in a safe and intelligent manner
Pre-condition: Data is successfully published in the platform
Actors: Urban Platform
Rationale: When data is successfully submitted (either via APIs or manual upload), it is
processed/prepared for storage into the platforms database. This procedure will include the
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 21
generation of unique identifiers to the database, enrichment with ontologies (when applicable),
encrypted (when applicable), signed with digital certificates (when applicable) to ensure that the
data conforms to the platform data formatting, standards, security and regulation. Data may be
converted to accepted formats, as needed (e.g. graph model). A primary goal of the conversion of
content for the platform is the preservation of the content. Priority will be given to preserving the
data accordingly to the policies defined in section (2.6.2). Access-control levels and license models
are associated to data which is subject to restrictions relating to access and conditions of use.
Refines into requirements: FREQ 28 FREQ 39.
Use Case Basic Interactions and Responses
1. Platform mechanisms converts submitted data into a standard format
2. Security enforcement (e.g. anonymisation, cryptography) is placed on
sensitive information.
UC4. Store City 3. Platform associates with datasets the access-control definitions set by
Data owner of resources.
4. Data is enriched with semantics and is associated with other datasets
5. Platform stores data in a scalable and secure database.
6. End of data storage.
2.4.2 Use Case: Transmit Data
ID: UC5
Refines: SUB-GOAL 2: City data is managed in a safe and intelligent manner
Pre-condition: Data is successfully published in the platform
Actors: Urban Platform
Rationale: The platform accepts data retrieval request, validates users rights to access the data,
retrieves city data from data storage, and moves a copy of the data to the relevant platform
component for further processing. If special processing is required, the retrieval function accesses
data in staging storage and applies the requested processes. The types of operations, which may
be carried out, include sub-sampling in temporal or spatial dimensions, conversions between
different data types or output formats, and other specialized processing (e.g., data visualisation).
Once it is finalised data will be sent to the appropriate delivery channels (e.g. APIs, GUI). It also
encompasses function to verify corruption during any internal data transfer. This function requires
that all hardware and software within the platform provide notification of potential errors and that
these errors are routed to standard error logs that are checked by the Platform Provider.
Refines into requirements: FREQ 40 to 54.
2.4.3 Use Case: Manage Infrastructure
ID: UC6
Refines: SUB-GOAL 2: City data is managed in a safe and intelligent manner
Pre-condition: The platform is available
Actors: Urban Platform
Rationale: Manage infrastructure provides the services and functions for the overall operation of
the urban platform. Administration functions include monitoring quality of service agreements,
auditing data publication to ensure that they meet archive standards, and maintaining configuration
management of system hardware and software. In overall, it provides system engineering
functions to monitor and improve platform operations, and to inventory, report on, and
migrate/update the contents of the platforms databases.
Refines into requirements: FREQ 55 to 62.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 22
Use Case Basic Interactions and Responses
1. Platform keeps monitoring services at run-time to ensure operation
and integrity of city data
o If system failure, the platform activates mechanisms for recovery
UC6. Manage based on pre-defined rules
Infrastructure o Platform logs issue and issue alert messages to platform providers
2. Platform logs operation capabilities (e.g. performance, mean of time
failure, issues, etc.)
2.4.4 Functional Requirements
Req. ID UC. ID Description Priority Domain
A minimal set of identifying information/metadata concerning data Business Needs,
FREQ.28 UC4 Must
publication submission must be recorded. Platform
Stores and tracks versions of data. Links /connections between
FREQ.29 UC4 Must City Data, Platform
versions are created and maintained.
FREQ.30 UC4 Converts data to accepted file formats Must City Data, Platform
Keep sensitive information secured and accessible only to authorized
FREQ.31 UC4 Must City Data, Platform
users
FREQ.32 UC4 Keep users personal information protected Should City Data, Platform
FREQ.33 UC4 Keep city data and meta-data secured Must Platform Needs
FREQ.34 UC4 Enable privacy preserving mechanisms associated to data Must Platform Needs
FREQ.35 UC4 Model data in accordance with defined standards Must City Data, Platform
FREQ.36 UC4 Support the use of ontologies and semantic modelling of city data Could City Data
FREQ.37 UC4 Support database-level provenance annotation Should City Data
FREQ.38 UC4 Support data-level provenance annotation Should City Data
FREQ.39 UC4 Enable data to be encrypted Should Platform Needs
System must have the ability to search and display metadata, preferably
City Data, Platform
FREQ.40 UC5 in a user-conformable, human readable display as well as in its native Must
Needs
format for machine harvesting and manipulation.
Controls access to data in the repository based on multiple permission
City Data, Platform
FREQ.41 UC5 levels. These permission levels determine the create/edit/read/delete Should
Needs
privileges granted users.
Access rights and conditions of use will be held for each data and its City Data, Platform
FREQ.42 UC5 Should
related metadata. Needs
Access rights and conditions can be inherited from a parent data to any City Data, Platform
FREQ.43 UC5 Could
data designated as a child data (derived information). Needs
Access rights and conditions of use will be machine readable and City Data, Platform
FREQ.44 UC5 Should
actionable. Needs
Access mechanisms must be sufficiently granular to allow the Business Needs, City
FREQ.45 UC5 identification of individual users, in order to maintain audit logs of actions Should
Data, Platform
performed by users.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 23
Maintains the integrity of the database which contains both metadata
FREQ.46 UC5 and system information. Must Platform Needs
Provides internal validation such as referential integrity of the contents of City Data, Platform
FREQ.47 UC5 the database. Must
Needs
Creates and maintains schema definitions required to support data
FREQ.48 UC5 management functions. Must Platform Needs
Monitors and ensures that data and metadata are not corrupted during
FREQ.49 UC5 transfers. Must Platform Needs
Provides statistically acceptable assurance that no components of the
FREQ.50 UC5 data are corrupted during any internal data transfer. Must Platform Needs
Performs routine and special data integrity checking for each dataset
FREQ.51 UC5 and generates error reports. Must Platform Needs
Provides disaster recovery capabilities including data backup, off-site
FREQ.52 UC5 data storage, data recovery, etc. Must Platform Needs
Refresh/replace data without service interruption, and update
FREQ.53 UC5 corresponding metadata as appropriate. Must Platform Needs
Ensure that any associated unique identifiers of the updated data are not
FREQ.54 UC5 altered. Must Platform Needs
Audits submissions to ensure that they meet archive/repository
FREQ.55 UC6 standards. Must Platform Needs
Maintains configuration management of the system hardware and
FREQ.56 UC6 software. Must Platform Needs
Has capability to inventory, report on and migrate the contents of the
FREQ.57 UC6 repository. Must Platform Needs
FREQ.58 UC6 Ensures data integrity for version upgrades and format migration. Must Platform Needs
FREQ.59 UC6 Monitors functionality of the entire repository. Must Platform Needs
FREQ.60 UC6 Maintains integrity of system configuration. Must Platform Needs
Audits system operations, performance and usage.
FREQ.61 UC6 Must Platform Needs
Provides platform performance information and database holdings
FREQ.62 UC6 inventory reports Must Platform Needs
2.5 SUB-GOAL 3: City data is orchestrated in a marketplace
Rationale: The urban platform enables users to consume and publish data in a secure and privacy
protected manner.
Drivers: Ensure data is secured and the identity of users are preserved
Actions: For Sub-Goal 3 to be maintained in the long-run it requires the efficient realisation of use
cases: “Commercialise City Data” and “Commercialise Data Services”, as shown in Figure 7.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 24

View File

@@ -0,0 +1,700 @@
city data via data APIs 5. Platform quickly process users request for data publication
6. Platform validates data submitted
o If valid data, platform acknowledges data publication has
been successful
o If non-valid data, platform shows error message and returns
to step 1
End of data publication
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 18
2.3.3 Use Case: Manage Resources
ID: UC3
Refines: GOAL 1: City data is collected in an intelligent manner
Pre-condition: User successfully authenticates in the platform
Actors: City data publisher
Rationale: Manage resources provides the services and functions for updating, maintaining and
accessing both data and metadata, as well as tracking the usage of resources by users. Ideally
the owners of the resources should be the only authorised user to manage resources, and other
authorised users can track the usage of the resources in the platform. The platform must provide a
database update response indicating the status of the update, avoid update errors to be
propagated in the platform, and should keep an audit trail of all actions to enable rollback. Data
usage tracking includes performing queries on the data management data to generate result sets,
and producing reports from these result sets.
Specialised Use Cases: The Use Case Manage Resources data is distinguished into two
specialised Use Cases: “User manages resources (UC3.1)” and “User tracks resources usage
(UC3.2)”.
Subordinated Use Cases: “Transmit Data (UC5)”
Refines into requirements: FREQ.27 to FREQ.25.
Specialised Use Cases Basic Interactions and Responses
1. Platform provides user with an interface for resources
management (e.g. data and metadata, data usage)
2. User chooses to edit or delete data
3. If edit, user revise metadata associated with the data (license,
provenance, ownership, access-control, semantics);
UC3.1. User manages 4. If delete, user selects dataset(s) to be removed
resources 5. User confirms action
6. Platform quickly process users request
7. Platform confirms execution of request
o If valid request, platform acknowledges request has been
processed successfully
o If non-valid request, platform returns to step 1.
8. End of resources management
1. Platform provides user with an interface for resources
management (e.g. data and metadata, data usage)
2. User chooses to visualise usage information of a dataset
UC3.2. User tracks 3. Platform quickly process users request for data usage
resources usage information
4. Platform provides user with statistical information about data
usage and data users anonymised information
5. End of data usage tracking.
2.3.4 Functional Requirements
Req. ID UC. ID Description Priority Domain
Societal Needs,
FREQ.1 UC1 Allow data publishers to register to submit data for publication Must
Platform
Tracks data publication agreements between Data and Platform Business Needs,
FREQ.2 UC1 Must
Providers Platform
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 19
Store terms of agreements, and use them to monitor/review/process
FREQ.3 UC1 Must City Data, Platform
data submissions.
Able to add and edit terms of agreement, based on access of level of Business Needs,
FREQ.4 UC1 Must
user. Platform
FREQ.5 UC1 Data publications are managed and monitored Must City Data, Platform
Allow authenticated users from across different organisations to City Data, Platform,
FREQ.6 UC2 Must
publish city data Business Needs
Provide authorization mechanisms for users and sensors to publish
FREQ.7 UC2 Must City Data, Platform
city data
City Data, Platform,
FREQ.9 UC2 Provide mechanisms for static data publication Must
Business Needs
City Data, Platform,
FREQ.10 UC2 Provide mechanisms for real-time data publication Must
Business Needs
FREQ.11 UC2 Enable the publication of metadata Must City Data, Platform
FREQ.12 UC2 Maintain temporal information about the data Must City Data, Platform
FREQ.13 UC2 Support sensory data collection Must City Data, Platform
FREQ.14 UC2 Accepts content in numerous file types/formats Must City Data, Platform
Prompts a request for resubmission to the data provider if an error of
FREQ.15 UC2 Must City Data, Platform
data transmission or receipt occurs
FREQ.16 UC2 Enable the semantic description of connected devices Must City Data, Platform
FREQ.17 UC2 Gather data from authenticated and authorized devices Must City Data, Platform
FREQ.18 UC2 Validates automatically the successful transfer of the data Must City Data, Platform
FREQ.19 UC2 Performs virus checking on data Must City Data, Platform
Verifies the validity of the submission based on submitter, expected
FREQ.20 UC2 Must City Data, Platform
format, data quality, and completeness
Platform should have built-in checks on the incoming metadata. Data
FREQ.21 UC2 not containing the minimally defined set of attributes should be Must City Data, Platform
returned to the publisher for metadata enhancement.
System should have a user-friendly method of mapping non-standard
FREQ.22 UC2 Should City Data, Platform
metadata elements into approved standard elements.
Once ingested, metadata should be stored in a single common format.
FREQ.23 UC2 This format should be one that ensures against data loss, and allows a Must City Data, Platform
variety of access/distribution options
Data in the repository shall have sufficient technical metadata to
FREQ.24 UC2 assure functionality (e.g. viewing and display) to ensure accessibility Must City Data, Platform
and reusability.
Allows publishers to display and perform manual/visual quality control Business Needs, City
FREQ.25 UC2 Could
assurance via a user-friendly GUI Data, Platform
Business Needs, City
FREQ.26 UC2 Any errors shall prompt a request for resubmission of data Should
Data, Platform
FREQ.27 UC3 Enable data providers to manage their resources Must Business Needs
A minimal set of identifying information/metadata concerning data Business Needs,
FREQ.28 UC3 Must
publication submission must be recorded Platform
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 20
Stores and tracks versions of data. Links /connections between
FREQ.29 UC3 Must City Data, Platform
versions are created and maintained
Give service and data providers access to anonymized data of the Business Needs
FREQ.30 UC3 Should
subscribers of their data or services
City Data, Platform,
FREQ.31 UC3 Enable data providers to maintain and repair data and metadata Should
Business Needs
Tracks data publication agreements between Data and Platform Business Needs,
FREQ.32 UC3 Must
Providers Platform
Store terms of agreements, and use them to monitor/review/process
FREQ.33 UC3 Must City Data, Platform
data submissions.
Able to add and edit terms of agreement, based on access of level of Business Needs,
FREQ.34 UC3 Must
user. Platform
FREQ.35 UC3 Submission volumes and schedules are managed and monitored Must City Data, Platform
2.4 SUB-GOAL 2: City data is managed in a safe and intelligent manner
Rationale: The urban platform enables users to publish, consume and commercialise data, as well
as deploy and manage services all in a secure and privacy protected manner.
Achieve [City data is exploited
to its full effect]
Goal
co-ena bles
Maintain [Resources are managed in a
safe and intelligent manner]
S ub-Goal 1
Achieve [Store Data] Achieve [Transmit Data] Achieve [Manage Infrastructure]
UC4 UC5 UC6
Figure 6. Sub-Goal 2 “City data is managed in a safe and intelligent manner” refinement.
Drivers: Ensure data is secured and the identity of users are preserved
Actions: For Sub-Goal 2 to be maintained in the long-run it requires the efficient realisation of use
cases: “Store City Data” and “Retrieve and Transmit City Data”, as shown in Figure 6.
2.4.1 Use Case: Store City Data
ID: UC4
Refines: SUB-GOAL 2: City data is managed in a safe and intelligent manner
Pre-condition: Data is successfully published in the platform
Actors: Urban Platform
Rationale: When data is successfully submitted (either via APIs or manual upload), it is
processed/prepared for storage into the platforms database. This procedure will include the
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 21
generation of unique identifiers to the database, enrichment with ontologies (when applicable),
encrypted (when applicable), signed with digital certificates (when applicable) to ensure that the
data conforms to the platform data formatting, standards, security and regulation. Data may be
converted to accepted formats, as needed (e.g. graph model). A primary goal of the conversion of
content for the platform is the preservation of the content. Priority will be given to preserving the
data accordingly to the policies defined in section (2.6.2). Access-control levels and license models
are associated to data which is subject to restrictions relating to access and conditions of use.
Refines into requirements: FREQ 28 FREQ 39.
Use Case Basic Interactions and Responses
1. Platform mechanisms converts submitted data into a standard format
2. Security enforcement (e.g. anonymisation, cryptography) is placed on
sensitive information.
UC4. Store City 3. Platform associates with datasets the access-control definitions set by
Data owner of resources.
4. Data is enriched with semantics and is associated with other datasets
5. Platform stores data in a scalable and secure database.
6. End of data storage.
2.4.2 Use Case: Transmit Data
ID: UC5
Refines: SUB-GOAL 2: City data is managed in a safe and intelligent manner
Pre-condition: Data is successfully published in the platform
Actors: Urban Platform
Rationale: The platform accepts data retrieval request, validates users rights to access the data,
retrieves city data from data storage, and moves a copy of the data to the relevant platform
component for further processing. If special processing is required, the retrieval function accesses
data in staging storage and applies the requested processes. The types of operations, which may
be carried out, include sub-sampling in temporal or spatial dimensions, conversions between
different data types or output formats, and other specialized processing (e.g., data visualisation).
Once it is finalised data will be sent to the appropriate delivery channels (e.g. APIs, GUI). It also
encompasses function to verify corruption during any internal data transfer. This function requires
that all hardware and software within the platform provide notification of potential errors and that
these errors are routed to standard error logs that are checked by the Platform Provider.
Refines into requirements: FREQ 40 to 54.
2.4.3 Use Case: Manage Infrastructure
ID: UC6
Refines: SUB-GOAL 2: City data is managed in a safe and intelligent manner
Pre-condition: The platform is available
Actors: Urban Platform
Rationale: Manage infrastructure provides the services and functions for the overall operation of
the urban platform. Administration functions include monitoring quality of service agreements,
auditing data publication to ensure that they meet archive standards, and maintaining configuration
management of system hardware and software. In overall, it provides system engineering
functions to monitor and improve platform operations, and to inventory, report on, and
migrate/update the contents of the platforms databases.
Refines into requirements: FREQ 55 to 62.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 22
Use Case Basic Interactions and Responses
1. Platform keeps monitoring services at run-time to ensure operation
and integrity of city data
o If system failure, the platform activates mechanisms for recovery
UC6. Manage based on pre-defined rules
Infrastructure o Platform logs issue and issue alert messages to platform providers
2. Platform logs operation capabilities (e.g. performance, mean of time
failure, issues, etc.)
2.4.4 Functional Requirements
Req. ID UC. ID Description Priority Domain
A minimal set of identifying information/metadata concerning data Business Needs,
FREQ.28 UC4 Must
publication submission must be recorded. Platform
Stores and tracks versions of data. Links /connections between
FREQ.29 UC4 Must City Data, Platform
versions are created and maintained.
FREQ.30 UC4 Converts data to accepted file formats Must City Data, Platform
Keep sensitive information secured and accessible only to authorized
FREQ.31 UC4 Must City Data, Platform
users
FREQ.32 UC4 Keep users personal information protected Should City Data, Platform
FREQ.33 UC4 Keep city data and meta-data secured Must Platform Needs
FREQ.34 UC4 Enable privacy preserving mechanisms associated to data Must Platform Needs
FREQ.35 UC4 Model data in accordance with defined standards Must City Data, Platform
FREQ.36 UC4 Support the use of ontologies and semantic modelling of city data Could City Data
FREQ.37 UC4 Support database-level provenance annotation Should City Data
FREQ.38 UC4 Support data-level provenance annotation Should City Data
FREQ.39 UC4 Enable data to be encrypted Should Platform Needs
System must have the ability to search and display metadata, preferably
City Data, Platform
FREQ.40 UC5 in a user-conformable, human readable display as well as in its native Must
Needs
format for machine harvesting and manipulation.
Controls access to data in the repository based on multiple permission
City Data, Platform
FREQ.41 UC5 levels. These permission levels determine the create/edit/read/delete Should
Needs
privileges granted users.
Access rights and conditions of use will be held for each data and its City Data, Platform
FREQ.42 UC5 Should
related metadata. Needs
Access rights and conditions can be inherited from a parent data to any City Data, Platform
FREQ.43 UC5 Could
data designated as a child data (derived information). Needs
Access rights and conditions of use will be machine readable and City Data, Platform
FREQ.44 UC5 Should
actionable. Needs
Access mechanisms must be sufficiently granular to allow the Business Needs, City
FREQ.45 UC5 identification of individual users, in order to maintain audit logs of actions Should
Data, Platform
performed by users.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 23
Maintains the integrity of the database which contains both metadata
FREQ.46 UC5 and system information. Must Platform Needs
Provides internal validation such as referential integrity of the contents of City Data, Platform
FREQ.47 UC5 the database. Must
Needs
Creates and maintains schema definitions required to support data
FREQ.48 UC5 management functions. Must Platform Needs
Monitors and ensures that data and metadata are not corrupted during
FREQ.49 UC5 transfers. Must Platform Needs
Provides statistically acceptable assurance that no components of the
FREQ.50 UC5 data are corrupted during any internal data transfer. Must Platform Needs
Performs routine and special data integrity checking for each dataset
FREQ.51 UC5 and generates error reports. Must Platform Needs
Provides disaster recovery capabilities including data backup, off-site
FREQ.52 UC5 data storage, data recovery, etc. Must Platform Needs
Refresh/replace data without service interruption, and update
FREQ.53 UC5 corresponding metadata as appropriate. Must Platform Needs
Ensure that any associated unique identifiers of the updated data are not
FREQ.54 UC5 altered. Must Platform Needs
Audits submissions to ensure that they meet archive/repository
FREQ.55 UC6 standards. Must Platform Needs
Maintains configuration management of the system hardware and
FREQ.56 UC6 software. Must Platform Needs
Has capability to inventory, report on and migrate the contents of the
FREQ.57 UC6 repository. Must Platform Needs
FREQ.58 UC6 Ensures data integrity for version upgrades and format migration. Must Platform Needs
FREQ.59 UC6 Monitors functionality of the entire repository. Must Platform Needs
FREQ.60 UC6 Maintains integrity of system configuration. Must Platform Needs
Audits system operations, performance and usage.
FREQ.61 UC6 Must Platform Needs
Provides platform performance information and database holdings
FREQ.62 UC6 inventory reports Must Platform Needs
2.5 SUB-GOAL 3: City data is orchestrated in a marketplace
Rationale: The urban platform enables users to consume and publish data in a secure and privacy
protected manner.
Drivers: Ensure data is secured and the identity of users are preserved
Actions: For Sub-Goal 3 to be maintained in the long-run it requires the efficient realisation of use
cases: “Commercialise City Data” and “Commercialise Data Services”, as shown in Figure 7.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 24
Achieve [City data is exploited
to its full effect]
Goal
co-ena bles
Maintain [City data is orchestrated in
a marketplace]
S ub-Goal 3
Achieve [Commercialise Data
Achieve [Commercialise City Data]
Services]
UC7 UC8
Figure 7. Sub-Goal 3 “City data is orchestrated in a marketplace” refinement.
2.5.1 Use Case: Commercialise City Data
ID: UC7
Refines: SUB-GOAL 3: City data is orchestrated in a marketplace
Pre-condition: Data is successfully published in the platform, both publisher and consumers of
city data are authenticated in the platform, and there are billing capabilities available.
Actors: Data Publishers, Data Consumers
Rationale: The providers of city data can commercialise city data based on the policies and
financial models defined in the platform. After publishing their data, publishers can define which
data can be available as open data and which data should be available with the payment of a
subscription fee. Once publishers define which data is to be commercially exploited, the platform
will associate the data with their respective financial models and let it ready for subscription. City
data consumer chooses which data to purchase and is redirected to a billing interface where the
subscription payment is taken. The platform must provide an update response indicating the status
of the payment. If successful, data is ready available to be consumed by humans and machines,
otherwise the user can re-try the payment or cancel transaction.
Commercialise city data also involves the function of managing commercial data. It provides
services and functions for updating, maintaining and accessing both data and its respective
commercial transactions. Furthermore, it enables data providers to track the usage of commercial
data by users. Ideally the owners of the data should be the only authorised user to manage
resources, and other authorised users can track the usage of the data in the platform. Data usage
tracking includes performing queries on the data management data to generate result sets, and
producing reports from these result sets. Data consumers are provided with functions which enable
them to manage their subscriptions and financial transactions on the platform. These functions
include updating, maintaining and accessing financial transactions. For all these functions and
services, the platform must provide a database update response indicating the status of the
update, avoid update errors to be propagated in the platform, and should keep an audit trail of all
actions to enable rollback.
Specialised Use Cases: The Use Case Commercialise City Data is distinguished into four
specialised Use Cases: “Commercialise Data (UC7.1)”, “Consume Commercial City Data (UC7.2)”,
“Manage Commercial Data (UC7.3)” and “Manage Data Subscription (UC7.4)”.
Refines into requirements: FREQ 63 to 68.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 25
Use Case Basic Interactions and Responses
1. User selects the data to be commercialised
2. User selects the commercial model for data consumption
UC7.1. 3. Platform validates selection
Commercialise 4. Platform associates data to subscription model
Data 5. Platform releases data for commercial exploitation in the marketplace
6. End of data commercialisation set up.
1. User selects the data to be subscribed to
2. User request subscription to data
UC7.2. 3. Platform validates selection
Consume 4. Platform redirects user to billing system
Proprietary 5. Billing system deals with user request
Data o If successful, user is redirected to a GUI where data is ready to use
o If unsuccessful, user can try payment again or cancel request
2. End of data subscription.
1. Platform provides user with an interface for commercial data
management
2. User chooses to edit or delete commercial data
o If edit, user revise commercial models, licenses, access-control,
semantics;
o If delete, user selects dataset(s) to be removed (following policies
UC7.3. Manage defined in the platform for data removal)
commercial 3. User confirms action
Data 4. Platform promptly process users request
5. Platform confirms execution of request
o If valid request, platform acknowledges request has been
processed successfully
o If non-valid request, platform returns to step 1.
6. End of resources management
1. Platform provides user with an interface for data subscription
management
2. User chooses to edit or cancel data subscription
o If edit, user revise payment and subscription timeframe;
o If cancel, user selects dataset(s) to have subscription cancelled
UC7.4. Manage (following policies defined in the platform for data subscription)
data 3. User confirms action
subscription 4. Platform promptly process users request
5. Platform confirms execution of request
o If valid request, platform updates acknowledges request has been
processed successfully
o If non-valid request, platform returns to step 1.
6. End of data subscription management
2.5.2 Use Case: Commercialise Data Services
ID: UC8
Refines: SUB-GOAL 3: City data is orchestrated in a marketplace
Pre-condition: Data is successfully published in the platform, both publisher and consumers of
city data are authenticated in the platform, and there are billing capabilities available.
Actors: Data Service Providers, Data Publishers and Consumers
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 26
Rationale: After deploying data services in the platform, the providers of data services can choose
to commercialise services based on the policies and financial models defined in the platform. Once
data service providers define which service(s) is (are) to be commercially exploited, the platform
will associate the services with their respective financial models and let available in the platform
applications module ready for use. User (either publisher or consumer) chooses which data
services to use, and in case a charged service is selected the platform redirects the user to a
billing interface where the payment is taken. The platform must provide an update response
indicating the status of the payment. If successful, service is ready available to be used, otherwise
the user can re-try the payment or cancel transaction. Note that data service owners should be
able to waive the payment of tariff to certain users categories.
Data services providers are offered with functions to manage their commercial services. The
platform provides functions for updating, maintaining and accessing both service and its respective
commercial transactions. Furthermore, it enables data services providers to track the usage of
services by users. Services usage tracking includes performing queries on the platform to
generate result sets, and producing reports from these result sets. The consumers of data services
are provided with functions which enable them to manage their subscriptions and financial
transactions. These functions include updating, maintaining and accessing financial transactions.
For all these functions and services, the platform must provide a database update response
indicating the status of the update, avoid update errors to be propagated in the platform, and
should keep an audit trail of all actions to enable rollback.
Specialised Use Cases: The Use Case Commercialise Data Services is distinguished into four
specialised Use Cases: “Commercialise Data Services (UC8.1)”, “Consume Data Services
(UC8.2)”, “Manage Commercial Services (UC8.3)” and “Manage Services Subscription (UC8.4)”.
Refines into requirements: FREQ 68 to 73.
Use Case Basic Interactions and Responses
1. User selects the data services to be commercialised
2. User selects the commercial model for data service usage based on the
category of users
UC8.1. 3. Platform validates selection
Commercialise 4. Platform associates data services to subscription model
Data Services 5. Platform enables data service to be commercially exploited in the
marketplace
6. End of services commercialisation set up.
1. User selects the data service to be subscribed to
2. User request subscription to service
3. Platform validates selection
UC8.2. 4. Platform validates users category its respective commercial models
Consume Data 4. If applicable, platform redirects user to billing system
Services 5. Billing system deals with users request
o If successful, user is redirected to a GUI where data is ready to use
o If unsuccessful, user can try payment again or cancel request
6. End of data subscription.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 27
1. Platform provides user with an interface for commercial data
management
2. User chooses to edit or delete commercial data
o If edit, user revise commercial models, licenses, access-control,
semantics;
o If delete, user selects dataset(s) to be removed (following policies
UC8.3. Manage defined in the platform for data removal)
commercial 3. User confirms action
services 4. Platform promptly process users request
5. Platform confirms execution of request
o If valid request, platform acknowledges request has been
processed successfully
o If non-valid request, platform returns to step 1.
6. End of resources management
1. Platform provides user with an interface for data subscription
management
2. User chooses to edit or cancel data subscription
o If edit, user revise payment and subscription timeframe;
o If cancel, user selects dataset(s) to have subscription cancelled
UC8.4. Manage (following policies defined in the platform for data subscription)
services 3. User confirms action
subscription 4. Platform promptly process users request
5. Platform confirms execution of request
o If valid request, platform updates acknowledges request has been
processed successfully
o If non-valid request, platform returns to step 1.
6. End of data subscription management
2.5.3 Functional Requirements
Req. ID UC. ID Description Priority Domain
City Data, Platform,
FREQ.63 UC7 Support the commercialization of city data Should Business Needs
City Data, Platform,
FREQ.64 UC7 Enable users to subscribe to city data through the payment of a tariff Should Business Needs
City Data, Platform,
FREQ.65 UC7 Enable users to manage their data subscriptions Should Business
Provide platform providers mechanisms to define the terms and
FREQ.66 UC7 Must Platform Needs
conditions for platform data usage
Enable data providers to manage the subscription models of their City Data, Platform,
FREQ.67 UC7 Should
data Business
UC7/ City Data, Platform,
FREQ.68 Utilise secure and reliable billing and payment management systems Must
UC8 Business
City Data, Platform,
FREQ.69 UC8 Support the commercialization of data services Should Business Needs
Enable data providers to manage the commercial models of their City Data, Platform,
FREQ.70 UC8 Should
services Business Needs
Provide service providers mechanisms to define the terms and City Data, Platform,
FREQ.71 UC8 Should
conditions of platform services Business Needs
Allow users to pay a tariff for using certain advanced services (e.g. City Data, Platform,
FREQ.72 UC8 Should
Data manipulation, enrichment) Business Needs
City Data, Platform,
FREQ.73 UC8 Enable users to manage their data services subscriptions Should Business Needs
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 28
2.6 SUB-GOAL 4: City data is offered in an accessible manner
Rationale: The urban platform provides city data in both human and machine (e.g. sensors,
actuators, systems) readable and understandable formats.
Drivers: Ensure data understandability and machine-to-machine data transaction.
Actions: For Sub-Goal 3 to be maintained in the long-run it requires the efficient realisation of use
cases: “Register Consumer”, “Discover City Data”, and “Consume City Data” as shown in Figure 8.
Achieve [City data is exploited
to its full effect]
Goal
co-ena bles
Maintain [City data is offered in an
accessible manner]
S ub-Goal 1
Achieve [Register Consumer] Achieve [Discover City Data] Achieve [Consume City Data]
UC9 UC10 UC11
Figure 8. Sub-Goal 4 “City data is offered in an accessible manner” refinement.
2.6.1 Use Case: Register Data Consumer
ID: UC9
Refines: SUB-GOAL 4: City data is offered in an accessible manner
Pre-condition: User is not logged in the platform
Actors: Data Consumers
Rationale: Data Consumers can register in the platform and request approval to consume city data
via GUI or APIs. They provide valid registration details (to be defined) and wait for platform to
confirm their registration. Users must accept the terms and conditions of platform usage and define
how their personal data can be used by the Platform Owner. Users can manage and alter their
registration information at any time they want to.
Refines into requirements: FREQ 64.
Use Case Basic Stimulus and Responses
1. The platform prompts the user for a username and password or register
new account.
2. The user selects registration option.
3. The platform prompts user for data consumer registration information
UC1. Register 4. The user enters in their information.
Consumer 5. Platform verifies information and creates account.
o If non-valid information, platform shows error message and returns to
step 1.
6. Platform acknowledges registration has been successful
7. End of registration
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 29
2.6.2 Use Case: Discover City Data
ID: UC10
Refines: SUB-GOAL 4: City data is offered in an accessible manner
Pre-condition: User has access to either platform GUI or API
Actors: Data Consumers
Rationale: Data Consumers can register in the platform and request approval to consume city data
via GUI or APIs. They provide valid registration details (to be defined) and wait for platform to
confirm their registration.
Refines into requirements: FREQ 64.
Use Case Basic Stimulus and Responses
1. Users access specialised data query end-points (e.g. SPARQL)
2. Users provides information for pre-defined parameters for search
3. Users request data search
4. Platform quickly process users request for data

View File

@@ -0,0 +1,604 @@
Consume City o If authentication is successful, users are provided with requested
Data via APIs data streams
3. Users are provided with requested data via APIs
2.6.4 Functional Requirements
Req. ID UC. ID Description Priority Domain
Allow users to register to use services and consume proprietary city Societal Needs,
FREQ.74 UC9 Should
data and open data (optional) Platform
Keep sensitive information secured and accessible only to Societal Needs,
FREQ.75 UC9 Should
authorized users Platform
Societal Needs,
FREQ.76 UC9 Provide authentication mechanisms for users Must Platform
Societal Needs,
FREQ.77 UC9 Keep users personal information protected Must Platform
Allow users to control which data they are willing to provide and how Societal Needs,
FREQ.78 UC9 Must
their data should be used Platform
Societal Needs,
FREQ.79 UC10 Allow users to format data in any supported data formats Must
Platform
The query request may require data to be sourced from different Societal Needs,
FREQ.80 UC10 Must
storage locations Platform
Allows query requests against all metadata used to manage the Societal Needs,
FREQ.81 UC10 repository. Should Platform
Provide users information about the legal aspects of the data Societal Needs,
FREQ.82 UC11 Must
(license, ownership) City Data
Societal Needs,
FREQ.83 UC11 Keeps an audit trail of all actions. Must City Data
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 31
2.7 SUB-GOAL 5: Users experience is enhanced by the provision of
value-added services
Rationale: The urban platform enables users to consume and publish data in a secure and privacy
protected manner
Drivers: Ensure data is secured and the identity of users are preserved
Actions: For Sub-Goal 5 to be maintained in the long-run it requires the efficient realisation of use
cases: “Deploy Data Services”, “Manage Services”, and “Utilise Data Services” as shown in Figure
8.
Achieve [City data is exploited
to its full effect]
Goal
co-ena bles
Maintain [User s experience is enhanced by
the provision of value-added services]
S ub-Goal 1
Achieve [Deploy Data Services] Achieve [Manage Services] Achieve [Utilise Data Services]
UC12 UC13 UC14
Figure 9. Sub-Goal 5 “Users experience is enhanced by the provision of value-added services” refinement
2.7.1 Deploy Data Services
ID: UC12
Refines: SUB-GOAL 5: Users experience is enhanced by the provision of value-added services
Pre-condition: Data Services Providers are provided with credentials, are authorised to deploy
their services in the platform, and have access to technical specifications of the platform interfaces.
Actors: Data Services Providers
Rationale: Data Services can register in the platform and request approval to deploy services in
the platform. They provide valid registration details (to be defined) and wait for registration
confirmation. Platform Providers may authorise or not data services providers to offer both open
and proprietary services in the platform. Data services providers must formally agree with service
deployment agreement with the Urban Platform. This agreement defines terms of the content,
policies, regulations, license agreement. The Urban Platform will proactively work with Service
Providers to agree on the technical specifications of interfaces and platform openness level.
Agreements between Platform and Data Service Providers may be renegotiated on a periodic or
ad-hoc basis.
Refines into requirements: FREQ.1 to FREQ.5.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 32
Use Case Basic Stimulus and Responses
1. User authenticates in the platform
2. User is provided access to platform interfaces for service deployment
3. User deploy services
4. Platform checks compatibility and any technical issues arising from the
UC12. Deploy new service
Services 5. If approved the service is ready to be used and managed in the
platform
o If deployment is not approved, platform shows error message and
returns to step 1.
6. End of deployment
2.7.2 Use Case: Manage Services
ID: UC13
Refines: GOAL 5: Users experience is enhanced by the provision of value-added services
Pre-condition: User successfully authenticates in the platform
Actors: Data Services Providers
Rationale: Manage services provides the functions for updating, maintaining and accessing
services as well as tracking their usage by users. Ideally the owners of the services should be the
only authorised user to manage them, and other authorised users can track the usage of the
services in the platform. In case of updates the platform must log in the database update details
and send to service providers a response indicating the status of the update. The platform should
also ensure update errors are not propagated nor affect the health of other services provided in the
platform, and should keep an audit trail of all actions to enable rollback. Data services usage
tracking includes performing queries on the data management data to generate result sets, and
producing reports from these result sets. All users information provided to service providers must
follow regulations of data protection and the users defined rules for their data use.
Specialised Use Cases: The Use Case Manage Services is distinguished into two specialised
Use Cases: “User manages services (UC13.1)” and “User tracks service usage (UC13.2)”.
Subordinated Use Cases: “Transmit Data (UC5)”
Refines into requirements: FREQ.27 to FREQ.25.
Specialised Use Cases Basic Interactions and Responses
1. Platform provides user with an interface for services management
2. User chooses to edit or delete services
3. If edit, user revise service information (access-control,
commercial models, parameters) and deployment;
If delete, user selects services to be removed / disabled
UC13.1. User manages 4. User confirms action
services 5. Platform quickly process users request
6. Platform confirms execution of request
o If valid request, platform acknowledges request has been
processed successfully
o If non-valid request, platform returns to step 1.
7. End of services management
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 33
1. Platform provides user with an interface for services management
2. User chooses to visualise usage information of a service
3. Platform quickly process users request for data usage
UC13.2. User tracks information
services usage 4. Platform provides user with statistical information about services
usage and data users anonymised information
5. End of data services tracking.
2.7.3 Use Case: Utilise Data Services
ID: UC2
Refines: SUB-GOAL 1 - City data is collected in an intelligent manner
Pre-condition: User is authenticated in the platform
Actors: City data publisher
Rationale: Data Consumers can register in the platform and request approval to consume city data via GUI
or APIs. They provide valid registration details (to be defined) and wait for platform to confirm their
registration.
Subordinated Use Cases: “Commercialise Data Services (UC8)”
Refines into requirements: FREQ 6 to FREQ.26.
Specialised Use Cases Basic Interactions and Responses
1. Users / Machines select data service to be utilised
2. Users / Machines are redirected to authentication mechanism in
UC2.1. User utilises data case of registration is needed for the particular service
services o If authentication is successful, users are provided with
requested data streams
3. Users are provided with requested service either via API or GUI
2.7.4 Functional Requirements
Req. ID UC. ID Description Priority Domain
Provide stable and well-defined interfaces to ensure interoperability
Societal Needs,
FREQ.84 UC12 between the platform, services and the applications provided by Should Platform
services providers
Ensure the interfaces of the architecture are open to reduce entry Societal Needs,
FREQ.85 UC12 Should
barriers and integration issues Platform
Provide multi-purposed and network intelligent interfaces to Societal Needs,
FREQ.86 UC12 Must
providers and consumers of services Platform
Provide service providers mechanisms to define the terms and Societal Needs,
FREQ.87 UC12 Must
conditions of platform services deployment Platform
Business Needs,
FREQ.88 UC13 Provide statistical information of users feedback on service usage Must Platform
Allow users to use services to manipulate city data (e.g. Create Societal Needs,
FREQ.89 UC10 Must
mash ups, integrate) Platform
Allow users to provide feedback on usability, and quality of data Societal Needs,
FREQ.90 UC14 Must
and services provided by the platform Platform
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 34
3. Non-functional Requirements
3.1 Run-time Quality Requirements
3.1.1 Scalability Requirements
Rationale: The ability of the system to execute its task within its expected performance profile and
to handle on-demand increased processing volumes of data and service requests
Drivers: Provide ready access to all data that underpins decision making processes in smart cities,
and accommodate users and data usage patterns
Refines into requirements: NFREQ.1, NFREQ.2, NFREQ.3, NFREQ.4
Relevance: Urban platforms have ambitious performance requirements. Such platforms must cope
with users demand for data and services, capture real-time data that will be catalysed by a myriad
of sensors. The demand for urban platform is very likely to significantly increase over time. It is
very difficult to have clear performance characteristics due to the ubiquity, heterogeneity high
connectivity of devices and end users.
SCALABILITY MEASURES
Actions Capture the performance requirements
Create service level agreements
Predict scalability using software simulation
Analyse the performance of the platform overtime
Conduct practical testing
Strategy Prioritize service and data requests
Distribute processing over time
Scale up or scale out as necessary
Reuse resources and results Partition and parallelize
Constantly monitor Quality of Service at runtime
3.1.2 Availability and Reliability Requirements
Rationale: The ability of the system to be fully or partly operational as and when required and to
effectively handle failures that could affect system availability
Drivers: Build a reliable foundation for “on demand” exploitation of data
Refines into requirements: NFREQ.5, NFREQ.6, NFREQ.7, NFREQ.8
Relevance: Any system that has complex or extended availability requirements, complex recovery
processes, or a high profile (e.g., is visible to the public)
AVAILABILITY AND RELIABILITY MEASURES
Actions Capture the availability requirements Produce the availability schedule
Estimate platform availability Estimate functional availability Assess against the
requirements Rework the architecture
Strategy Adopt fault-tolerant hardware
Use reliable infrastructure database
Log transactions
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 35
Develop adaptive software to cope and recover from faults
Design and test for failure
Deploy load balancing
Identify suitable backup and disaster recovery solution
3.1.3 Trust Requirements
Rationale: A quality related to the users belief in the reliability, integrity and ability of the functional
behaviour of the platform
Drivers: Gain understanding of what influences users experience while interacting with services
provided
Requirements: NFREQ.16, NFREQ.17
Relevance: Relevant to the systems that share and collect information that may raise public
concern. In some cases, trust has to do with the reliability of data and their providers, whereas in
other cases trust can be associated with the security and privacy of the technology that was
deployed. Trust affects the reputation of the platform besides its dissemination and maturity on the
market.
TRUST MEASURES
Capture trust requirements
Perform risk analysis so measures can be implemented
Actions Explore the vulnerability aspects of city data
Check whether extensibility requirements impact on trust
Define a trust model
Adopt trust model
Deploy monitoring capabilities and assess its impact on scalability
Manage the data in a way that ensures its compliance with data
Strategy protection regulations
Implement tampering and data misuse detection
Make use of Cryptography when necessary
Allow Federation of trust between platforms
3.1.4 Security Requirements
Rationale: Ability of the system to enforce the intended confidentiality, trust, integrity and service
and data access policies, and to detect and recover from failure in these security mechanisms.
Drivers: Manage the data and services in a way that ensures its integrity, and compliance with
data protection regulations
Relevance: Relevant to the systems that share and collect information that may raise public
concern. Urban platforms may become a valuable target for attackers which can potentially leave
huge swathes of information exposed. It could potentially undermine trust in the government and
damage its reputation.
Refines into requirements: NFREQ.9 to NFREQ.15
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 36
SECURITY MEASURES
Elicit the security requirements
Cross-check security requirements impact on services offered by different
providers
Verify security impact on service composition
Conduct risk analysis and impacts of security breach
Use scalable and efficient user authentication components
Use authentication and authorization components to secure interfacing with
Actions external services
Address aspects of data collection, storage and distribution
Address aspects of service and communication security among devices
Identify security requirements of the physical infrastructure
Balance and prioritize scalability (performance) and security requirements
Evaluate trade-offs between privacy considerations and preventing abuse. (While
anonymous access guarantees privacy of users, traceability of users due to abuse
of the service is not possible.)
Toughen users functional components
Authenticate subjects
Define and enforce access policies
Secure communication infrastructures
Secure interfaces with external systems and services
Strategy
Secure databases
Check data integrity for critical services
User digital certificates and encryption where necessary
Secure monetary transactions
Secure users personal information
3.1.5 Privacy Requirements
Rationale: Ability of the system to ensure that the collection and transmission of personal data is
minimized and handled in accordance with users expectation and regulations.
Drivers: Protect the vulnerability aspects volunteered citizens data
Requirements: NFREQ.18, NFREQ.19, NFREQ.20, NFREQ.21, NFREQ.22
Relevance: Ensuring users privacy is protected positively influences users experience,
acceptance and continuous use of the platform. Besides other factors, the reputation of the
platform depends on how well users information is secure and preserved.
PRIVACY MEASURES
Capture trust requirements
Perform risk analysis so measures can be implemented
Actions Explore the vulnerability aspects of city data
Check whether extensibility requirements impact on trust
Define a trust model
Allow users to interact with the platform anonymously in given
circumstances
Manage users identification securely
Strategy Anonymize data whenever necessary to comply with data regulations
Cryptograph personal identifiers during data transmission when that is
necessary
Avoid unauthorized access to implicit information (e.g. location)
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 37
Verify the impact of security, trust and scalability requirements trade-offs
on privacy
Allow the user to control how personal information is used
Empower user to control the data disclosure mechanism
3.2 Non Run-time Quality Requirements
3.2.1 Evolvability Requirements
Rationale: The ability of the platform to withstand and easily adapt when new requirements and
changes is introduced.
Drivers: Ensure the platform is able to accommodate additional functionality and emerging
technologies at later stage at a fair and transparent cost
Refines into requirements: NFREQ.23
Relevance: Important for longer- lived and more widely used systems. Urban platforms are
expected to be highly evolvable in order to accommodate future emerging technologies and avoid
interoperability issues.
EVOLVABILITY MEASURES
Actions Characterize and assess the evolution needs
Consider the evolution trade-offs
Balance and negotiate potential conflicting requirements emerging from
the evolution capability.
Strategy Adopt standards and open interfaces
Design loose-coupled components
Preserve the platform resilience
3.2.2 Extensibility Requirements
Rationale: The flexibility of the system to allow services and functionality to be extended and
augmented by service providers in order to increase value of services to both platform providers
and end-users. The extension of the platform services is determined by the Platform Openness
strategy.
Drivers: Stakeholders can extend the services provided by the urban platform, so that
partnerships can be built to deliver holistic and interoperable solutions. Identify integrated
approaches to design and service delivery which ensures that services fit together and that
synergies can be exploited.
Refines into requirements: NFREQ.24, NFREQ.25
Relevance: Important for longer- lived and more widely used systems. Urban platforms are
expected to be highly evolvable in order to accommodate future emerging technologies and avoid
interoperability issues.
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 38
EXTENSIBILITY
Actions Characterize and assess the extensibility needs
Trace the impacts and cost of extensions
Negotiate potential conflicting requirements emerging from adding extensions
in the platform
Strategy Develop a modular architecture with standard interfaces that reduces entry
barriers due to increased transparency and integration
Share technical information about interfaces will help service providers in
targeting opportunities around the platform
3.3 List of Non-Functional Requirements
ID # Description Concern Priority Domain
Platform,
NFREQ.1 Support different service level agreements (SLA) Scalability Should
Infrastructure
Platform,
NFREQ.2 Process services and events on a set of distributed nodes Scalability Should
Infrastructure
Platform,
NFREQ.3 Continuously monitor Quality of Service at runtime Scalability Should
Infrastructure
Platform,
NFREQ.4 Balance its load at runtime Scalability Should
Infrastructure
Platform,
NFREQ.5 Provide high availability Availability Should
Infrastructure
Platform,
NFREQ.6 Guarantee infrastructure availability Availability Should
Infrastructure
Platform,
NFREQ.7 Ensure network availability Availability Should
Infrastructure
Platform,
NFREQ.8 Be able to perform self-healing Availability Should
Infrastructure
City Data,
NFREQ.9 Expose data and services to authorized users Security Must
Platform
City Data,
NFREQ.10 Ensure services are always accessible to entitled users Security Must
Platform
NFREQ.11 Ensure Data Freshness Security Must Platform
NFREQ.12 Support access control mechanisms Security Must Platform
Platform,
NFREQ.13 Have security mechanisms to protect data transmission Security Should
Infrastructure
Platform,
NFREQ.14 Make it difficult to spy on communicated messages Security Should
Infrastructure
Platform,
NFREQ.15 Be able to perform to detect threats at runtime Security Should
Infrastructure
Provide trusted and secure communication and information Platform,
NFREQ.16 Trust Should
management Infrastructure
NFREQ.17 The platform infrastructure and services shall be trustable Trust Should Infrastructure
Societal Needs,
NFREQ.18 Allow users to use free services anonymously Privacy Should
Platform
Societal Needs,
NFREQ.19 Allow people to use free services anonymously Privacy Should
Platform
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 39
Allow users to control which data they are willing to provide Societal Needs,
NFREQ.20 Privacy Should
and how their data should be used Platform
NFREQ.21 Keep users access-control rights/ policies secured. Privacy Should Platform
Provide privacy protection for users interacting with the Societal Needs,
NFREQ.22 Privacy Should
platform Platform
Platform,
NFREQ.23 Provide communication confidentiality Privacy Should
Infrastructure
Societal Needs,
NFREQ.24 Be extensible for future technologies. Evolvability Must City Data, Platform,
Infrastructure
Platform,
NFREQ.26 Provide standard interfaces for service providers Extensibility Should
Business Needs
NFREQ.26 Be able to provide services in an interoperable manner Extensibility Should Platform
4. Other Requirements
4.1 Minimal Descriptive Metadata Required from Data Provider
Minimal Descriptive Metadata Required from Data Provider
Attribute Required Definition Notes Examples
Database Name Y A name given to the resource
Author Name of a person or body associated with
Y
the creation of the resource
Maintainer Name of the entity responsible for making
Y
the resource available
Date Created Y Date the dataset was created
Date Modified Y Date the dataset was modified
Last Revision Y Date the dataset was last revised
Update Frequency Y Frequency of data maintenance
Mode of Release Y Open/Proprietary
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 40
4.2 Urban Platform Supported Data Formats
MIME type Description Extensions Level
application/json JavaScript Object Notation json supported
application/xml eXtensible markup language file xml supported
text/csv Comma separated values file csv supported
5. Conclusion & Forward Plans
This document represents the first set of requirements specification for urban platform. Future
activities will collaboratively assess, resolve requirements conflicts, prioritize, and validate the
requirements of the urban platform. Ultimately, this document will become a complete final
requirements specification document to guide and speed up the development open platform for
cities. Table below shows the milestones, deliverables and engagement activities completed and
yet to be completed by the Demand Side Engagement Stream.
Milestones, deliverables and engagement activity Forecast date Status
Stakeholders invitation Late Completed
September/2015
Online Workshop 1: Project Scope and Outcomes 20/11/2015 Completed
Online meeting held with city members to communicate goals,
expected outcomes, time commitment and required actions.
Start of Collaborative Requirements Engineering Process 20/11/2015 Completed
Participants reviewed the first draft of urban platform requirements,
provided comments, and suggested new requirements and changes.
Online Workshop 2: Review and Refine Requirements 08/12/2015 Completed
Participants had a conference call to review the requirements
specification document and provide their comments.
Deliverable: Requirements Specification Document v2.1 shared 05/01/2016 Completed
across the Working Streams for consultation
Online Workshop 3: Review Requirements Specification 12/01/2016 Completed
Document and discussion of Letter of Intent
Participants had a conference call to review the requirements
specification document and provide their comments, and discussed
the Letter of Intent to be signed by Mayor/Equiv of EU cities to
commit to application of common U.P. approach.
Urban Platforms Workshop in Brussels 19/01/2016 Completed
Participants provided feedback on the requirements specification
document and recommended changes in the document
Requirements Specification for Urban Platforms (EIP_SCC Initiative) Page 41
Deliverable: Updated Requirements Specification Document v2.2 29/01/2016 Completed
shared with Industry and Standardisation Working Streams
Deliverable: Online release of the Requirements Specification Early
Document and open calls for wider consultation on the Requirements February/2016
Online Workshop 4: Engagement with Industry Side Early
Capture industry feedback on the Requirements Specification February/2016
Document to assess its suitability to drive the development of the first
draft reference architecture.
Online Workshop 5: Review Requirements Specification Mid
Document v2.2 and discuss requirement prioritization and February/2016
balancing
Collectively determine which candidate requirements of urban
platforms should be prioritized as high importance to all the cities
(use of Value Oriented Prioritization Method). Requirements are also
prioritized to minimize risk during development of urban platforms so
that the most important requirements are made explicit and
considered in the reference architecture.
Capture of case studies from cities intended to support requirements Mid March/2016
validation (City of Porto), and learning and confidence building
amongst cities.

File diff suppressed because it is too large Load Diff

View File

@@ -3,6 +3,7 @@ package agent
import ( import (
"context" "context"
"fmt" "fmt"
"runtime"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@@ -32,6 +33,29 @@ type Orchestrator struct {
enableCapabilityGap bool enableCapabilityGap bool
log *logger.Logger log *logger.Logger
skillsMu sync.RWMutex skillsMu sync.RWMutex
pendingFilesMu sync.Mutex
pendingFiles map[string][]pendingFileRef
}
type pendingFileRef struct {
ID string
Name string
MimeType string
}
type capabilityRoutingResult struct {
NeedSkills bool
SelectedToolNames []string
SelectedSkills []knowledge.Skill
Reason string
UsedFallback bool
}
type filePromptContext struct {
Summary string
FatalReason string
FileIDs []string
Uploaded []pendingFileRef
} }
// NewOrchestrator 创建一个新的编排器对象,初始化关键路径和超时控制等。 // NewOrchestrator 创建一个新的编排器对象,初始化关键路径和超时控制等。
@@ -76,6 +100,7 @@ func NewOrchestrator(
reactMaxStep: reactMaxStep, reactMaxStep: reactMaxStep,
enableCapabilityGap: enableCapabilityGap, enableCapabilityGap: enableCapabilityGap,
log: log, log: log,
pendingFiles: make(map[string][]pendingFileRef),
} }
} }
@@ -85,12 +110,20 @@ func NewOrchestrator(
// - 是否需要调用工具action + action_input // - 是否需要调用工具action + action_input
// 循环持续进行,直到 LLM 返回 is_final_answer=true。 // 循环持续进行,直到 LLM 返回 is_final_answer=true。
func (o *Orchestrator) HandleMessage(ctx context.Context, chatID, userID, text string) (string, error) { func (o *Orchestrator) HandleMessage(ctx context.Context, chatID, userID, text string) (string, error) {
return o.handleMessageInternal(ctx, chatID, userID, text, nil)
}
func (o *Orchestrator) HandleMessageWithFiles(ctx context.Context, chatID, userID, text string, files []llm.InputFile) (string, error) {
return o.handleMessageInternal(ctx, chatID, userID, text, files)
}
func (o *Orchestrator) handleMessageInternal(ctx context.Context, chatID, userID, text string, files []llm.InputFile) (string, error) {
// 为链路追踪设置唯一的 TraceID // 为链路追踪设置唯一的 TraceID
traceID := logger.NewTraceID() traceID := logger.NewTraceID()
ctx = logger.WithTraceID(ctx, traceID) ctx = logger.WithTraceID(ctx, traceID)
traceLogPrefix := "trace_id=" + traceID traceLogPrefix := "trace_id=" + traceID
if o.log != nil { if o.log != nil {
o.log.Infof("%s handle message chat_id=%s user_id=%s text_len=%d", traceLogPrefix, chatID, userID, len(text)) o.log.Infof("%s handle message chat_id=%s user_id=%s text_len=%d files=%d", traceLogPrefix, chatID, userID, len(text), len(files))
o.log.Debugf("%s handle message text=%q", traceLogPrefix, text) o.log.Debugf("%s handle message text=%q", traceLogPrefix, text)
} }
@@ -111,6 +144,38 @@ func (o *Orchestrator) HandleMessage(ctx context.Context, chatID, userID, text s
return report, nil return report, nil
} }
trimmedText := strings.TrimSpace(text)
isFileOnly := len(files) > 0 && trimmedText == ""
if isFileOnly {
if err := o.store.SaveMessage(chatID, userID, "user", "[FILE_UPLOAD]"); err != nil {
if o.log != nil {
o.log.Errorf("%s save file-only user marker failed chat_id=%s err=%v", traceLogPrefix, chatID, err)
}
return "", err
}
uploadCtx := o.prepareFilePromptContext(ctx, files, nil)
if strings.TrimSpace(uploadCtx.FatalReason) != "" {
finalText := "文件上传失败,无法建立文档上下文。" + "\n" + uploadCtx.FatalReason
if err := o.store.SaveMessage(chatID, userID, "assistant", finalText); err != nil && o.log != nil {
o.log.Warnf("%s save upload failure message failed chat_id=%s err=%v", traceLogPrefix, chatID, err)
}
return finalText, nil
}
o.appendPendingFiles(chatID, userID, uploadCtx.toPendingRefs())
finalText := o.buildFileUploadAck(uploadCtx)
if err := o.store.SaveMessage(chatID, userID, "assistant", finalText); err != nil {
if o.log != nil {
o.log.Errorf("%s save file upload ack failed chat_id=%s err=%v", traceLogPrefix, chatID, err)
}
return "", err
}
if o.log != nil {
o.log.Infof("%s file-only message handled chat_id=%s cached_files=%d", traceLogPrefix, chatID, len(uploadCtx.FileIDs))
}
return finalText, nil
}
// 保存用户消息到 SQLite 中 // 保存用户消息到 SQLite 中
if err := o.store.SaveMessage(chatID, userID, "user", text); err != nil { if err := o.store.SaveMessage(chatID, userID, "user", text); err != nil {
if o.log != nil { if o.log != nil {
@@ -133,13 +198,30 @@ func (o *Orchestrator) HandleMessage(ctx context.Context, chatID, userID, text s
} }
// 进入统一 ReAct 循环 // 进入统一 ReAct 循环
response, err := o.runUnifiedReAct(ctx, chatID, userID, compressed, text) pendingRefs := o.getPendingFiles(chatID, userID)
fileCtx := o.prepareFilePromptContext(ctx, files, pendingRefs)
if strings.TrimSpace(fileCtx.FatalReason) != "" {
finalText := "文件上传失败,无法继续进行文档解析。" + "\n" + fileCtx.FatalReason
if err := o.store.SaveMessage(chatID, userID, "assistant", finalText); err != nil && o.log != nil {
o.log.Warnf("%s save assistant failure message failed chat_id=%s err=%v", traceLogPrefix, chatID, err)
}
if o.log != nil {
o.log.Warnf("%s stop before react due to file upload failure reason=%s", traceLogPrefix, fileCtx.FatalReason)
}
return finalText, nil
}
routeInput := composeRouteInput(text, fileCtx.Summary)
route := o.routeCapabilities(ctx, routeInput)
response, err := o.runUnifiedReAct(ctx, chatID, userID, compressed, text, fileCtx, routeInput, route)
if err != nil { if err != nil {
if o.log != nil { if o.log != nil {
o.log.Errorf("%s message generation failed chat_id=%s err=%v", traceLogPrefix, chatID, err) o.log.Errorf("%s message generation failed chat_id=%s err=%v", traceLogPrefix, chatID, err)
} }
return "", err return "", err
} }
if len(pendingRefs) > 0 {
o.clearPendingFiles(chatID, userID)
}
// 最终将机器人的回复也加入记忆缓存 // 最终将机器人的回复也加入记忆缓存
if err := o.store.SaveMessage(chatID, userID, "assistant", response); err != nil { if err := o.store.SaveMessage(chatID, userID, "assistant", response); err != nil {
@@ -156,21 +238,29 @@ func (o *Orchestrator) HandleMessage(ctx context.Context, chatID, userID, text s
} }
// buildUnifiedSystemPrompt 构建统一 ReAct 循环的 system prompt。 // buildUnifiedSystemPrompt 构建统一 ReAct 循环的 system prompt。
// 包含人格设定、所有可用技能(含完整内容)、所有可用工具、以及 JSON 输出格式约束 // 工具始终可用技能仅按当前问题挑选相关项作为增强上下文
func (o *Orchestrator) buildUnifiedSystemPrompt() string { func (o *Orchestrator) buildUnifiedSystemPrompt(userInput string, route capabilityRoutingResult) string {
skillMetaDoc := o.formatSkillSummariesForPrompt() skillMetaDoc := o.formatSkillSummariesForPrompt()
allSkillsDoc := o.formatAllSkillsContent() relevantSkillsDoc := o.formatSelectedSkillsForPrompt(userInput, route.SelectedSkills)
toolDoc := o.formatToolDoc() toolDoc := o.formatToolDoc()
runtimeDoc := formatRuntimeContextForPrompt()
routeDoc := formatRouteForPrompt(route)
return strings.Join([]string{ return strings.Join([]string{
"你是一个个人自动化助手,必须遵循如下人格设定并保持一致:", "你是一个个人自动化助手,必须遵循如下人格设定并保持一致:",
o.soul, o.soul,
"", "",
"===== 运行环境 =====",
runtimeDoc,
"",
"===== 可用技能概览 =====", "===== 可用技能概览 =====",
skillMetaDoc, skillMetaDoc,
"", "",
"===== 技能详细说明 =====", "===== 能力路由结果 =====",
allSkillsDoc, routeDoc,
"",
"===== 本轮相关技能(按用户问题筛选) =====",
relevantSkillsDoc,
"", "",
"===== 可用工具 =====", "===== 可用工具 =====",
toolDoc, toolDoc,
@@ -190,25 +280,32 @@ func (o *Orchestrator) buildUnifiedSystemPrompt() string {
"决策规则:", "决策规则:",
"1) 如果你可以直接回答用户问题(不需要任何工具):", "1) 如果你可以直接回答用户问题(不需要任何工具):",
" 设 is_final_answer=trueaction=\"none\"final_answer 填写完整回复。", " 设 is_final_answer=trueaction=\"none\"final_answer 填写完整回复。",
"2) 如果你需要调用工具获取信息后才能回答:", "2) 优先判断是否可通过原子工具能力完成任务;若可完成,直接进行工具调用链路。",
"3) 当纯工具调用无法满足时,再结合已加载的技能详细说明进行决策。",
"4) 如果你需要调用工具获取信息后才能回答:",
" 设 is_final_answer=falseaction 填工具名action_input 填工具所需输入final_answer=null。", " 设 is_final_answer=falseaction 填工具名action_input 填工具所需输入final_answer=null。",
"3) 不要在 JSON 之外输出任何内容。", "5) 不要在 JSON 之外输出任何内容。",
"4) 根据技能说明中的指引决定何时以及如何使用工具。", "6) 根据技能说明中的指引决定何时以及如何使用工具。",
"5) 每轮工具调用结果会以 Observation 的形式追加到推理记录中,供你下一轮决策参考。", "7) 工具能力是全局可用的,不依赖技能命中;当技能不匹配时,仍可直接选择合适工具。",
"8) 若技能中存在与当前运行环境不匹配的章节(如 Windows 专章),应降低优先级,除非用户明确要求该环境。",
"9) 每轮工具调用结果会以 Observation 的形式追加到推理记录中,供你下一轮决策参考。",
}, "\n") }, "\n")
} }
// runUnifiedReAct 执行统一的 ReAct 循环。 // runUnifiedReAct 执行统一的 ReAct 循环。
// LLM 每次都看到完整的技能集+工具集,自行决定是否调用工具或直接回答。 // LLM 每次都看到完整的技能集+工具集,自行决定是否调用工具或直接回答。
// 循环持续到 is_final_answer=true 或达到安全上限。 // 循环持续到 is_final_answer=true 或达到安全上限。
func (o *Orchestrator) runUnifiedReAct(ctx context.Context, chatID, userID, compressedContext, userInput string) (string, error) { func (o *Orchestrator) runUnifiedReAct(ctx context.Context, chatID, userID, compressedContext, userInput string, fileCtx filePromptContext, routeInput string, route capabilityRoutingResult) (string, error) {
traceID := logger.TraceIDFromContext(ctx) traceID := logger.TraceIDFromContext(ctx)
traceLogPrefix := "trace_id=" + traceID traceLogPrefix := "trace_id=" + traceID
systemPrompt := o.buildUnifiedSystemPrompt() if strings.TrimSpace(routeInput) == "" {
routeInput = composeRouteInput(userInput, fileCtx.Summary)
}
systemPrompt := o.buildUnifiedSystemPrompt(routeInput, route)
if o.log != nil { if o.log != nil {
o.log.Infof("%s unified react start", traceLogPrefix) o.log.Infof("%s unified react start route_need_skills=%v route_tools=%v route_skills=%d fallback=%v", traceLogPrefix, route.NeedSkills, route.SelectedToolNames, len(route.SelectedSkills), route.UsedFallback)
} }
// 安全上限:防止无限循环(当前暂不使用 reactMaxStep 配置约束,使用固定硬上限) // 安全上限:防止无限循环(当前暂不使用 reactMaxStep 配置约束,使用固定硬上限)
@@ -229,13 +326,16 @@ func (o *Orchestrator) runUnifiedReAct(ctx context.Context, chatID, userID, comp
"用户问题:", "用户问题:",
userInput, userInput,
"", "",
"文件上下文:",
defaultIfEmpty(fileCtx.Summary, "(none)"),
"",
"当前推理记录(按时间顺序):", "当前推理记录(按时间顺序):",
scratchpad, scratchpad,
"", "",
"请输出你的 JSON 决策。", "请输出你的 JSON 决策。",
}, "\n") }, "\n")
raw, err := o.llm.Generate(ctx, systemPrompt, prompt) raw, err := o.generateWithOptionalFiles(ctx, systemPrompt, prompt, fileCtx.FileIDs)
if err != nil { if err != nil {
return "", err return "", err
} }
@@ -335,15 +435,514 @@ func (o *Orchestrator) runUnifiedReAct(ctx context.Context, chatID, userID, comp
return "我尝试了多轮推理与工具调用,但仍未得到稳定结论。请给我更具体的约束或允许我继续尝试。", nil return "我尝试了多轮推理与工具调用,但仍未得到稳定结论。请给我更具体的约束或允许我继续尝试。", nil
} }
// formatAllSkillsContent 返回所有技能的完整内容,用于注入到 system prompt 中。 func composeRouteInput(userInput, fileSummary string) string {
func (o *Orchestrator) formatAllSkillsContent() string { userInput = strings.TrimSpace(userInput)
skills := o.getSkillsSnapshot() fileSummary = strings.TrimSpace(fileSummary)
if userInput == "" {
return fileSummary
}
if fileSummary == "" {
return userInput
}
return userInput + "\n\n" + fileSummary
}
func (o *Orchestrator) prepareFilePromptContext(ctx context.Context, files []llm.InputFile, pending []pendingFileRef) filePromptContext {
ctxOut := filePromptContext{}
if len(pending) > 0 {
for _, p := range pending {
id := strings.TrimSpace(p.ID)
if id == "" {
continue
}
ctxOut.FileIDs = append(ctxOut.FileIDs, id)
}
}
if len(files) == 0 {
ctxOut.Summary = buildFileSummary(pending, nil)
return ctxOut
}
uploader, ok := o.llm.(llm.FileUploader)
if !ok {
return filePromptContext{FatalReason: "检测到文件输入,但当前 LLM 客户端不支持文件上传接口。"}
}
uploaded := make([]pendingFileRef, 0, len(files))
for i, f := range files {
if strings.TrimSpace(f.FileName) == "" || len(f.Content) == 0 {
return filePromptContext{FatalReason: fmt.Sprintf("file[%d] 缺少文件名或内容,无法上传。", i+1)}
}
fileID, err := uploader.UploadFile(ctx, f, "file-extract")
if err != nil {
return filePromptContext{FatalReason: fmt.Sprintf("file[%d] name=%s 上传失败: %v", i+1, f.FileName, err)}
}
ctxOut.FileIDs = append(ctxOut.FileIDs, fileID)
uploaded = append(uploaded, pendingFileRef{
ID: fileID,
Name: strings.TrimSpace(f.FileName),
MimeType: defaultIfEmpty(strings.TrimSpace(f.MimeType), "application/octet-stream"),
})
}
ctxOut.Uploaded = uploaded
ctxOut.Summary = buildFileSummary(pending, uploaded)
return ctxOut
}
func buildFileSummary(pending, uploaded []pendingFileRef) string {
if len(pending) == 0 && len(uploaded) == 0 {
return ""
}
lines := make([]string, 0, len(pending)+len(uploaded)+2)
lines = append(lines, "以下文件 file_id 可用于本轮问答:")
idx := 1
for _, p := range pending {
id := strings.TrimSpace(p.ID)
if id == "" {
continue
}
lines = append(lines, fmt.Sprintf("- cached_file[%d] name=%s mime=%s file_id=%s", idx, defaultIfEmpty(strings.TrimSpace(p.Name), "(unknown)"), defaultIfEmpty(strings.TrimSpace(p.MimeType), "application/octet-stream"), id))
idx++
}
for _, p := range uploaded {
id := strings.TrimSpace(p.ID)
if id == "" {
continue
}
lines = append(lines, fmt.Sprintf("- uploaded_file[%d] name=%s mime=%s file_id=%s", idx, defaultIfEmpty(strings.TrimSpace(p.Name), "(unknown)"), defaultIfEmpty(strings.TrimSpace(p.MimeType), "application/octet-stream"), id))
idx++
}
if len(lines) == 1 {
return ""
}
return strings.Join(lines, "\n")
}
func (o *Orchestrator) generateWithOptionalFiles(ctx context.Context, systemPrompt, userPrompt string, fileIDs []string) (string, error) {
ids := nonEmptyIDs(fileIDs)
if len(ids) == 0 {
return o.llm.Generate(ctx, systemPrompt, userPrompt)
}
client, ok := o.llm.(llm.FileChatClient)
if !ok {
return o.llm.Generate(ctx, systemPrompt, userPrompt)
}
return client.GenerateWithFiles(ctx, systemPrompt, userPrompt, ids)
}
func (o *Orchestrator) buildFileUploadAck(ctx filePromptContext) string {
if len(ctx.FileIDs) == 0 {
return "文件已接收,但未拿到有效 file_id。请重新上传一次。"
}
lines := []string{
fmt.Sprintf("文件上传完成,已缓存 %d 个 file_id。", len(ctx.FileIDs)),
"请继续发送你的问题,我会结合这些文件内容和历史对话一起回答。",
}
if strings.TrimSpace(ctx.Summary) != "" {
lines = append(lines, "", ctx.Summary)
}
return strings.Join(lines, "\n")
}
func nonEmptyIDs(ids []string) []string {
if len(ids) == 0 {
return nil
}
out := make([]string, 0, len(ids))
seen := map[string]struct{}{}
for _, id := range ids {
id = strings.TrimSpace(id)
if id == "" {
continue
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
out = append(out, id)
}
return out
}
func (c filePromptContext) toPendingRefs() []pendingFileRef {
if len(c.Uploaded) > 0 {
copied := make([]pendingFileRef, len(c.Uploaded))
copy(copied, c.Uploaded)
return sanitizePendingRefs(copied)
}
ids := nonEmptyIDs(c.FileIDs)
out := make([]pendingFileRef, 0, len(ids))
for _, id := range ids {
out = append(out, pendingFileRef{ID: id})
}
return out
}
func (o *Orchestrator) appendPendingFiles(chatID, userID string, refs []pendingFileRef) {
refs = sanitizePendingRefs(refs)
if len(refs) == 0 {
return
}
key := pendingFileKey(chatID, userID)
o.pendingFilesMu.Lock()
defer o.pendingFilesMu.Unlock()
merged := append(o.pendingFiles[key], refs...)
o.pendingFiles[key] = sanitizePendingRefs(merged)
}
func (o *Orchestrator) getPendingFiles(chatID, userID string) []pendingFileRef {
key := pendingFileKey(chatID, userID)
o.pendingFilesMu.Lock()
defer o.pendingFilesMu.Unlock()
snapshot := o.pendingFiles[key]
out := make([]pendingFileRef, len(snapshot))
copy(out, snapshot)
return out
}
func (o *Orchestrator) clearPendingFiles(chatID, userID string) {
key := pendingFileKey(chatID, userID)
o.pendingFilesMu.Lock()
defer o.pendingFilesMu.Unlock()
delete(o.pendingFiles, key)
}
func pendingFileKey(chatID, userID string) string {
return strings.TrimSpace(chatID) + "::" + strings.TrimSpace(userID)
}
func sanitizePendingRefs(refs []pendingFileRef) []pendingFileRef {
if len(refs) == 0 {
return nil
}
out := make([]pendingFileRef, 0, len(refs))
seen := map[string]struct{}{}
for _, r := range refs {
id := strings.TrimSpace(r.ID)
if id == "" {
continue
}
if _, ok := seen[id]; ok {
continue
}
seen[id] = struct{}{}
r.ID = id
r.Name = strings.TrimSpace(r.Name)
r.MimeType = strings.TrimSpace(r.MimeType)
out = append(out, r)
}
return out
}
func defaultIfEmpty(v, fallback string) string {
if strings.TrimSpace(v) == "" {
return fallback
}
return v
}
// formatRelevantSkillsForPrompt 返回与当前用户问题最相关的技能内容。
func (o *Orchestrator) formatSelectedSkillsForPrompt(userInput string, selected []knowledge.Skill) string {
skills := selected
if len(skills) == 0 { if len(skills) == 0 {
return "(none)" skills = o.selectRelevantSkills(userInput, 4)
}
if len(skills) == 0 {
return "(none matched, tools are still globally available)"
} }
return formatSkills(skills) return formatSkills(skills)
} }
func (o *Orchestrator) routeCapabilities(ctx context.Context, userInput string) capabilityRoutingResult {
fallback := capabilityRoutingResult{
NeedSkills: true,
SelectedSkills: o.selectRelevantSkills(userInput, 4),
Reason: "router fallback: keyword matching",
UsedFallback: true,
}
raw, err := o.llm.Generate(ctx, o.buildRouteSystemPrompt(), o.buildRouteUserPrompt(userInput))
if err != nil {
if o.log != nil {
o.log.Warnf("capability router llm call failed err=%v", err)
}
return fallback
}
decision, err := parseCapabilityRoute(raw)
if err != nil {
if o.log != nil {
o.log.Warnf("capability router parse failed err=%v raw=%q", err, raw)
}
return fallback
}
resolvedTools := o.normalizeToolSelection(decision.SelectedTools)
resolved := capabilityRoutingResult{
NeedSkills: decision.NeedSkills,
SelectedToolNames: resolvedTools,
Reason: strings.TrimSpace(decision.Reason),
}
if resolved.NeedSkills {
skills := o.resolveSkillsByNames(decision.SelectedSkills, 4)
if len(skills) == 0 {
skills = o.selectRelevantSkills(userInput, 4)
resolved.UsedFallback = true
}
resolved.SelectedSkills = skills
}
return resolved
}
func (o *Orchestrator) buildRouteSystemPrompt() string {
return strings.Join([]string{
"你是能力路由器Router Agent。",
"你的任务是:在不加载技能全文的前提下,仅根据工具摘要和技能摘要,判断本请求是否可以仅靠原子工具能力完成,还是需要加载技能详细说明。",
"输出必须且仅能是 JSON",
"{",
" \"need_skills\": true 或 false,",
" \"selected_tools\": [\"tool_name\", ...],",
" \"selected_skills\": [\"skill_name\", ...],",
" \"reason\": \"简短路由理由\"",
"}",
"规则:",
"1) 优先原子工具能力。若可通过工具链路完成need_skills=false。",
"2) 只有当工具能力不足以覆盖业务约束时need_skills=true 并选择少量最相关技能。",
"3) selected_skills 仅填写技能名称(来自技能摘要)。",
"4) selected_tools 仅填写可用工具名。",
"5) 不要输出 JSON 之外内容。",
}, "\n")
}
func (o *Orchestrator) buildRouteUserPrompt(userInput string) string {
return strings.Join([]string{
"当前运行环境:",
formatRuntimeContextForPrompt(),
"",
"用户问题:",
userInput,
"",
"可用工具摘要:",
o.formatToolDoc(),
"",
"可用技能摘要:",
o.formatSkillSummariesForPrompt(),
"",
"请给出路由 JSON。",
}, "\n")
}
func (o *Orchestrator) normalizeToolSelection(in []string) []string {
if len(in) == 0 {
return nil
}
allowed := map[string]struct{}{}
for _, t := range o.tools.List() {
allowed[strings.ToLower(strings.TrimSpace(t.Name()))] = struct{}{}
}
out := make([]string, 0, len(in))
set := map[string]struct{}{}
for _, name := range in {
n := strings.ToLower(strings.TrimSpace(name))
if n == "" {
continue
}
if _, ok := allowed[n]; !ok {
continue
}
if _, exists := set[n]; exists {
continue
}
set[n] = struct{}{}
out = append(out, n)
}
sort.Strings(out)
return out
}
func (o *Orchestrator) resolveSkillsByNames(names []string, maxCount int) []knowledge.Skill {
if len(names) == 0 {
return nil
}
if maxCount <= 0 {
maxCount = 4
}
all := o.getSkillsSnapshot()
idx := make(map[string]knowledge.Skill, len(all))
for _, sk := range all {
key := strings.ToLower(strings.TrimSpace(sk.Name))
if key != "" {
idx[key] = sk
}
}
out := make([]knowledge.Skill, 0, maxCount)
used := map[string]struct{}{}
for _, name := range names {
key := strings.ToLower(strings.TrimSpace(name))
if key == "" {
continue
}
sk, ok := idx[key]
if !ok {
continue
}
if _, exists := used[key]; exists {
continue
}
used[key] = struct{}{}
out = append(out, sk)
if len(out) >= maxCount {
break
}
}
return out
}
func formatRouteForPrompt(route capabilityRoutingResult) string {
b := strings.Builder{}
if route.UsedFallback {
b.WriteString("router_status: fallback\n")
} else {
b.WriteString("router_status: ok\n")
}
b.WriteString("need_skills: ")
b.WriteString(strconv.FormatBool(route.NeedSkills))
b.WriteString("\n")
b.WriteString("selected_tools: ")
if len(route.SelectedToolNames) == 0 {
b.WriteString("(none)")
} else {
b.WriteString(strings.Join(route.SelectedToolNames, ", "))
}
b.WriteString("\n")
b.WriteString("selected_skill_count: ")
b.WriteString(strconv.Itoa(len(route.SelectedSkills)))
b.WriteString("\n")
if strings.TrimSpace(route.Reason) != "" {
b.WriteString("reason: ")
b.WriteString(strings.TrimSpace(route.Reason))
}
return strings.TrimSpace(b.String())
}
func (o *Orchestrator) selectRelevantSkills(userInput string, maxCount int) []knowledge.Skill {
if maxCount <= 0 {
maxCount = 4
}
query := strings.TrimSpace(strings.ToLower(userInput))
all := o.getSkillsSnapshot()
if query == "" || len(all) <= maxCount {
return all
}
queryTokens := buildQueryTokens(query)
type item struct {
skill knowledge.Skill
score int
}
ranked := make([]item, 0, len(all))
for _, sk := range all {
hay := strings.ToLower(sk.Name + "\n" + clipForScoring(sk.Content, 1800))
score := 0
if strings.Contains(hay, query) {
score += 8
}
for _, tk := range queryTokens {
if strings.Contains(hay, tk) {
score++
}
}
if score == 0 {
continue
}
ranked = append(ranked, item{skill: sk, score: score})
}
if len(ranked) == 0 {
return nil
}
sort.Slice(ranked, func(i, j int) bool {
if ranked[i].score == ranked[j].score {
return strings.ToLower(strings.TrimSpace(ranked[i].skill.Name)) < strings.ToLower(strings.TrimSpace(ranked[j].skill.Name))
}
return ranked[i].score > ranked[j].score
})
if len(ranked) > maxCount {
ranked = ranked[:maxCount]
}
out := make([]knowledge.Skill, 0, len(ranked))
for _, r := range ranked {
out = append(out, r.skill)
}
return out
}
func buildQueryTokens(query string) []string {
set := map[string]struct{}{}
collectToken := func(t string) {
t = strings.TrimSpace(t)
if len([]rune(t)) < 2 {
return
}
set[t] = struct{}{}
}
for _, part := range strings.FieldsFunc(query, func(r rune) bool {
if r >= 'a' && r <= 'z' {
return false
}
if r >= '0' && r <= '9' {
return false
}
if r >= 0x4e00 && r <= 0x9fff {
return false
}
return true
}) {
collectToken(part)
}
// 针对中文无空格输入,补充 2-gram 提升匹配命中率。
runes := []rune(query)
for i := 0; i+1 < len(runes); i++ {
r1 := runes[i]
r2 := runes[i+1]
if (r1 >= 0x4e00 && r1 <= 0x9fff) && (r2 >= 0x4e00 && r2 <= 0x9fff) {
collectToken(string([]rune{r1, r2}))
}
}
out := make([]string, 0, len(set))
for tk := range set {
out = append(out, tk)
}
sort.Strings(out)
return out
}
func clipForScoring(s string, maxRunes int) string {
if maxRunes <= 0 {
maxRunes = 1800
}
r := []rune(s)
if len(r) <= maxRunes {
return s
}
return string(r[:maxRunes])
}
func formatRuntimeContextForPrompt() string {
goos := strings.TrimSpace(strings.ToLower(runtime.GOOS))
if goos == "" {
goos = "unknown"
}
return "当前运行系统 GOOS=" + goos + "。请优先使用与该系统一致的策略。仅当用户明确要求时,才采用其他系统(如 Windows的专用流程。"
}
// emitCapabilityGap 处理能力缺口信息埋点或者通过 AI 自动创建生成相应缺失技能的逻辑 // emitCapabilityGap 处理能力缺口信息埋点或者通过 AI 自动创建生成相应缺失技能的逻辑
func (o *Orchestrator) emitCapabilityGap(chatID, userID, intent, reason string) { func (o *Orchestrator) emitCapabilityGap(chatID, userID, intent, reason string) {
if !o.enableCapabilityGap { if !o.enableCapabilityGap {

View File

@@ -0,0 +1,48 @@
package agent
import (
"runtime"
"strings"
"testing"
"laodingbot/internal/knowledge"
)
func TestBuildQueryTokensIncludesChineseBigrams(t *testing.T) {
tokens := buildQueryTokens("请执行命令并查看文件")
joined := strings.Join(tokens, ",")
if !strings.Contains(joined, "命令") {
t.Fatalf("expected token contains 命令, got: %v", tokens)
}
if !strings.Contains(joined, "文件") {
t.Fatalf("expected token contains 文件, got: %v", tokens)
}
}
func TestSelectRelevantSkillsPrefersMatchingSkill(t *testing.T) {
o := &Orchestrator{
skills: []knowledge.Skill{
{Name: "文件系统查询专家", Content: "适用于目录、文件、路径、命令执行等场景"},
{Name: "天气查询", Content: "用于天气和空气质量查询"},
{Name: "日程助手", Content: "用于日程管理"},
},
}
selected := o.selectRelevantSkills("帮我执行命令查看某个文件", 2)
if len(selected) == 0 {
t.Fatal("expected non-empty selected skills")
}
if selected[0].Name != "文件系统查询专家" {
t.Fatalf("expected top skill 文件系统查询专家, got: %s", selected[0].Name)
}
if len(selected) > 2 {
t.Fatalf("expected at most 2 skills, got: %d", len(selected))
}
}
func TestFormatRuntimeContextForPromptIncludesGOOS(t *testing.T) {
doc := formatRuntimeContextForPrompt()
if !strings.Contains(strings.ToLower(doc), strings.ToLower(runtime.GOOS)) {
t.Fatalf("expected runtime context contains GOOS=%s, got: %s", runtime.GOOS, doc)
}
}

View File

@@ -0,0 +1,31 @@
package agent
import (
"encoding/json"
"fmt"
"strings"
)
type capabilityRouteDecision struct {
NeedSkills bool `json:"need_skills"`
SelectedTools []string `json:"selected_tools"`
SelectedSkills []string `json:"selected_skills"`
Reason string `json:"reason"`
}
func parseCapabilityRoute(raw string) (capabilityRouteDecision, error) {
raw = normalizeJSON(raw)
start := strings.Index(raw, "{")
end := strings.LastIndex(raw, "}")
if start < 0 || end < start {
return capabilityRouteDecision{}, fmt.Errorf("no json object found")
}
raw = raw[start : end+1]
var out capabilityRouteDecision
if err := json.Unmarshal([]byte(raw), &out); err != nil {
return capabilityRouteDecision{}, err
}
out.Reason = strings.TrimSpace(out.Reason)
return out, nil
}

View File

@@ -0,0 +1,34 @@
package agent
import "testing"
func TestParseCapabilityRoute(t *testing.T) {
raw := `{"need_skills":true,"selected_tools":["shell"],"selected_skills":["文件系统查询专家"],"reason":"需要技能约束"}`
out, err := parseCapabilityRoute(raw)
if err != nil {
t.Fatalf("parseCapabilityRoute error: %v", err)
}
if !out.NeedSkills {
t.Fatal("expected need_skills=true")
}
if len(out.SelectedTools) != 1 || out.SelectedTools[0] != "shell" {
t.Fatalf("unexpected selected_tools: %#v", out.SelectedTools)
}
if len(out.SelectedSkills) != 1 || out.SelectedSkills[0] != "文件系统查询专家" {
t.Fatalf("unexpected selected_skills: %#v", out.SelectedSkills)
}
}
func TestParseCapabilityRouteCodeFence(t *testing.T) {
raw := "```json\n{\"need_skills\":false,\"selected_tools\":[\"file\",\"shell\"],\"selected_skills\":[],\"reason\":\"工具足够\"}\n```"
out, err := parseCapabilityRoute(raw)
if err != nil {
t.Fatalf("parseCapabilityRoute error: %v", err)
}
if out.NeedSkills {
t.Fatal("expected need_skills=false")
}
if len(out.SelectedTools) != 2 {
t.Fatalf("unexpected selected_tools len: %d", len(out.SelectedTools))
}
}

View File

@@ -6,6 +6,7 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io" "io"
"mime/multipart"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@@ -18,6 +19,20 @@ type Client interface {
Generate(ctx context.Context, systemPrompt, userPrompt string) (string, error) Generate(ctx context.Context, systemPrompt, userPrompt string) (string, error)
} }
type FileChatClient interface {
GenerateWithFiles(ctx context.Context, systemPrompt, userPrompt string, fileIDs []string) (string, error)
}
type FileUploader interface {
UploadFile(ctx context.Context, file InputFile, purpose string) (string, error)
}
type InputFile struct {
FileName string
MimeType string
Content []byte
}
type OpenAICompatibleClient struct { type OpenAICompatibleClient struct {
baseURL string baseURL string
apiKey string apiKey string
@@ -43,27 +58,64 @@ type chatRequest struct {
type chatMessage struct { type chatMessage struct {
Role string `json:"role"` Role string `json:"role"`
Content string `json:"content"` Content any `json:"content"`
}
type chatContentPart struct {
Type string `json:"type"`
Text string `json:"text,omitempty"`
FileID string `json:"file_id,omitempty"`
} }
type chatResponse struct { type chatResponse struct {
Choices []struct { Choices []struct {
Message chatMessage `json:"message"` Message struct {
Role string `json:"role"`
Content string `json:"content"`
} `json:"message"`
} `json:"choices"` } `json:"choices"`
Error *struct { Error *struct {
Message string `json:"message"` Message string `json:"message"`
} `json:"error,omitempty"` } `json:"error,omitempty"`
} }
type fileUploadResponse struct {
ID string `json:"id"`
Bytes int64 `json:"bytes,omitempty"`
CreatedAt int64 `json:"created_at,omitempty"`
Filename string `json:"filename,omitempty"`
Object string `json:"object,omitempty"`
Purpose string `json:"purpose,omitempty"`
Code int `json:"code,omitempty"`
Message string `json:"message,omitempty"`
Status any `json:"status,omitempty"`
StatusDetails any `json:"status_details,omitempty"`
Data *struct {
ID string `json:"id"`
} `json:"data,omitempty"`
Error *struct {
Message string `json:"message"`
} `json:"error,omitempty"`
}
func (c *OpenAICompatibleClient) Generate(ctx context.Context, systemPrompt, userPrompt string) (string, error) { func (c *OpenAICompatibleClient) Generate(ctx context.Context, systemPrompt, userPrompt string) (string, error) {
return c.generateInternal(ctx, systemPrompt, userPrompt, nil)
}
func (c *OpenAICompatibleClient) GenerateWithFiles(ctx context.Context, systemPrompt, userPrompt string, fileIDs []string) (string, error) {
return c.generateInternal(ctx, systemPrompt, userPrompt, fileIDs)
}
func (c *OpenAICompatibleClient) generateInternal(ctx context.Context, systemPrompt, userPrompt string, fileIDs []string) (string, error) {
if c.log != nil { if c.log != nil {
c.log.Debugf("llm request start model=%s system_len=%d user_len=%d", c.model, len(systemPrompt), len(userPrompt)) c.log.Debugf("llm request start model=%s system_len=%d user_len=%d file_count=%d", c.model, len(systemPrompt), len(userPrompt), len(fileIDs))
} }
userContent := buildUserContent(userPrompt, fileIDs)
body := chatRequest{ body := chatRequest{
Model: c.model, Model: c.model,
Messages: []chatMessage{ Messages: []chatMessage{
{Role: "system", Content: systemPrompt}, {Role: "system", Content: systemPrompt},
{Role: "user", Content: userPrompt}, {Role: "user", Content: userContent},
}, },
} }
b, err := json.Marshal(body) b, err := json.Marshal(body)
@@ -132,3 +184,144 @@ func (c *OpenAICompatibleClient) Generate(ctx context.Context, systemPrompt, use
return out.Choices[0].Message.Content, nil return out.Choices[0].Message.Content, nil
} }
func buildUserContent(userPrompt string, fileIDs []string) any {
trimmedPrompt := strings.TrimSpace(userPrompt)
if len(fileIDs) == 0 {
return userPrompt
}
parts := make([]chatContentPart, 0, len(fileIDs)+1)
if trimmedPrompt != "" {
parts = append(parts, chatContentPart{Type: "text", Text: userPrompt})
}
for _, id := range fileIDs {
id = strings.TrimSpace(id)
if id == "" {
continue
}
parts = append(parts, chatContentPart{Type: "file", FileID: id})
}
if len(parts) == 0 {
return userPrompt
}
return parts
}
func (c *OpenAICompatibleClient) UploadFile(ctx context.Context, file InputFile, purpose string) (string, error) {
if strings.TrimSpace(file.FileName) == "" {
return "", fmt.Errorf("empty file name")
}
if len(file.Content) == 0 {
return "", fmt.Errorf("empty file content")
}
purpose = strings.TrimSpace(purpose)
purposes := []string{}
if purpose != "" {
purposes = append(purposes, purpose)
}
// Provider compatibility fallback order.
purposes = appendIfMissing(purposes, "file-extract")
purposes = appendIfMissing(purposes, "batch")
var lastErr error
for _, p := range purposes {
fileID, err := c.uploadFileOnce(ctx, file, p)
if err == nil {
return fileID, nil
}
lastErr = err
if c.log != nil {
c.log.Warnf("llm file upload failed purpose=%s err=%v", p, err)
}
}
if lastErr == nil {
lastErr = fmt.Errorf("llm file upload failed: no purpose tried")
}
return "", lastErr
}
func (c *OpenAICompatibleClient) uploadFileOnce(ctx context.Context, file InputFile, purpose string) (string, error) {
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
if err := writer.WriteField("purpose", purpose); err != nil {
return "", err
}
part, err := writer.CreateFormFile("file", file.FileName)
if err != nil {
return "", err
}
if _, err := part.Write(file.Content); err != nil {
return "", err
}
if err := writer.Close(); err != nil {
return "", err
}
url := strings.TrimRight(c.baseURL, "/") + "/files"
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, body)
if err != nil {
return "", err
}
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Authorization", "Bearer "+c.apiKey)
resp, err := c.http.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()
raw, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
}
var out fileUploadResponse
if err := json.Unmarshal(raw, &out); err != nil {
return "", fmt.Errorf("llm file upload response decode failed: %w body=%s", err, clipForError(raw))
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
if strings.TrimSpace(out.Message) != "" {
return "", fmt.Errorf("llm file upload error: %s", out.Message)
}
if out.Error != nil && out.Error.Message != "" {
return "", fmt.Errorf("llm file upload error: %s", out.Error.Message)
}
return "", fmt.Errorf("llm file upload status: %d body=%s", resp.StatusCode, clipForError(raw))
}
fileID := strings.TrimSpace(out.ID)
if fileID == "" && out.Data != nil {
fileID = strings.TrimSpace(out.Data.ID)
}
if fileID == "" {
return "", fmt.Errorf("llm file upload returned empty file id body=%s", clipForError(raw))
}
if c.log != nil {
c.log.Infof("llm file uploaded name=%s size=%d file_id=%s purpose=%s status=%v", file.FileName, len(file.Content), fileID, purpose, out.Status)
}
return fileID, nil
}
func clipForError(raw []byte) string {
s := strings.TrimSpace(string(raw))
const max = 400
if len(s) <= max {
return s
}
return s[:max] + "...(truncated)"
}
func appendIfMissing(items []string, value string) []string {
value = strings.TrimSpace(value)
if value == "" {
return items
}
for _, it := range items {
if strings.EqualFold(strings.TrimSpace(it), value) {
return items
}
}
return append(items, value)
}

View File

@@ -9,6 +9,7 @@ import (
"laodingbot/internal/logger" "laodingbot/internal/logger"
"laodingbot/internal/tools" "laodingbot/internal/tools"
"laodingbot/tools/fileoperation" "laodingbot/tools/fileoperation"
"laodingbot/tools/git"
"laodingbot/tools/shell" "laodingbot/tools/shell"
"laodingbot/tools/websearch" "laodingbot/tools/websearch"
) )
@@ -16,6 +17,7 @@ import (
func RunChild(ctx context.Context, cfg config.Config, log *logger.Logger) error { func RunChild(ctx context.Context, cfg config.Config, log *logger.Logger) error {
var registryLog *logger.Logger var registryLog *logger.Logger
var fileLog *logger.Logger var fileLog *logger.Logger
var gitLog *logger.Logger
var shellLog *logger.Logger var shellLog *logger.Logger
var searchLog *logger.Logger var searchLog *logger.Logger
var serverLog *logger.Logger var serverLog *logger.Logger
@@ -23,12 +25,19 @@ func RunChild(ctx context.Context, cfg config.Config, log *logger.Logger) error
log.Infof("toolhost child starting") log.Infof("toolhost child starting")
registryLog = log.WithComponent("toolhost.registry") registryLog = log.WithComponent("toolhost.registry")
fileLog = log.WithComponent("toolhost.file") fileLog = log.WithComponent("toolhost.file")
gitLog = log.WithComponent("toolhost.git")
shellLog = log.WithComponent("toolhost.shell") shellLog = log.WithComponent("toolhost.shell")
searchLog = log.WithComponent("toolhost.websearch") searchLog = log.WithComponent("toolhost.websearch")
serverLog = log.WithComponent("toolhost.server") serverLog = log.WithComponent("toolhost.server")
} }
registry := tools.NewRegistry(registryLog) registry := tools.NewRegistry(registryLog)
registry.Register(fileoperation.New(cfg.Security.AllowedDirs, cfg.ToolOutputMaxChars, fileLog)) registry.Register(fileoperation.New(cfg.Security.AllowedDirs, cfg.ToolOutputMaxChars, fileLog))
registry.Register(git.New(
cfg.Security.WorkDir,
time.Duration(cfg.ToolCallTimeoutSec)*time.Second,
cfg.ToolOutputMaxChars,
gitLog,
))
registry.Register(shell.New( registry.Register(shell.New(
cfg.Security.AllowedCommands, cfg.Security.AllowedCommands,
cfg.Security.WorkDir, cfg.Security.WorkDir,

View File

@@ -4,6 +4,10 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"mime"
"os"
"path/filepath"
"strings" "strings"
"sync" "sync"
"time" "time"
@@ -34,9 +38,17 @@ type IncomingMessage struct {
MessageID string MessageID string
ChatID string ChatID string
UserID string UserID string
MsgType string
Text string Text string
FileName string
FileKey string
FileMime string
FileBytes []byte
FilePath string
} }
const maxFeishuFileBytes = 20 * 1024 * 1024
func NewBot(appID, appSecret, verifyToken, _ string, _ string, log *logger.Logger) (*Bot, error) { func NewBot(appID, appSecret, verifyToken, _ string, _ string, log *logger.Logger) (*Bot, error) {
if appID == "" || appSecret == "" { if appID == "" || appSecret == "" {
return nil, fmt.Errorf("empty feishu app credentials") return nil, fmt.Errorf("empty feishu app credentials")
@@ -66,7 +78,7 @@ func (b *Bot) Run(ctx context.Context, handler func(context.Context, IncomingMes
incoming, ok := parseIncoming(event) incoming, ok := parseIncoming(event)
if !ok { if !ok {
if b.log != nil { if b.log != nil {
b.log.Debugf("skip non-text or invalid feishu event") b.log.Debugf("skip unsupported or invalid feishu event")
} }
return nil return nil
} }
@@ -76,8 +88,11 @@ func (b *Bot) Run(ctx context.Context, handler func(context.Context, IncomingMes
} }
return nil return nil
} }
if incoming.MsgType == "file" {
b.enrichFileIncoming(evtCtx, &incoming)
}
if b.log != nil { if b.log != nil {
b.log.Infof("feishu message received message_id=%s chat_id=%s user_id=%s text=%s", incoming.MessageID, incoming.ChatID, incoming.UserID, incoming.Text) b.log.Infof("feishu message received message_id=%s chat_id=%s user_id=%s msg_type=%s text=%s", incoming.MessageID, incoming.ChatID, incoming.UserID, incoming.MsgType, incoming.Text)
} }
reply, err := handler(evtCtx, incoming) reply, err := handler(evtCtx, incoming)
if err != nil { if err != nil {
@@ -159,6 +174,175 @@ func extractText(content string) (string, error) {
return parsed.Text, nil return parsed.Text, nil
} }
func extractFileMeta(content string) (fileName string, fileKey string, err error) {
var parsed map[string]any
if err := json.Unmarshal([]byte(content), &parsed); err != nil {
return "", "", err
}
readString := func(keys ...string) string {
for _, key := range keys {
if v, ok := parsed[key]; ok {
s, ok := v.(string)
if ok {
trimmed := strings.TrimSpace(s)
if trimmed != "" {
return trimmed
}
}
}
}
return ""
}
fileName = readString("file_name", "fileName", "name", "filename")
fileKey = readString("file_key", "fileKey", "key")
return fileName, fileKey, nil
}
func buildFileRecognitionText(fileName, fileKey string) string {
if strings.TrimSpace(fileName) == "" {
fileName = "(unknown)"
}
if strings.TrimSpace(fileKey) == "" {
fileKey = "(unknown)"
}
return strings.Join([]string{
"用户发送了一条飞书文件消息。",
"文件名: " + fileName,
"文件Key: " + fileKey,
"系统将先上传该文件到 LLM Provider再由模型完成文档解析。若上传失败本次请求将直接中止。",
}, "\n")
}
func (b *Bot) enrichFileIncoming(ctx context.Context, incoming *IncomingMessage) {
if incoming == nil {
return
}
if strings.TrimSpace(incoming.MessageID) == "" || strings.TrimSpace(incoming.FileKey) == "" {
incoming.Text = buildFileRecognitionText(incoming.FileName, incoming.FileKey)
incoming.Text += "\n\n未找到完整 file_key 或 message_id暂时无法下载文件内容。"
return
}
content, fileName, err := b.downloadFileContent(ctx, incoming.MessageID, incoming.FileKey)
if err != nil {
if b.log != nil {
b.log.Warnf("feishu download file content failed message_id=%s file_key=%s err=%v", incoming.MessageID, incoming.FileKey, err)
}
incoming.Text = buildFileRecognitionText(incoming.FileName, incoming.FileKey)
incoming.Text += "\n\n文件下载失败: " + err.Error()
return
}
if strings.TrimSpace(fileName) != "" {
incoming.FileName = fileName
}
incoming.FileBytes = content
incoming.FileMime = detectMimeByName(incoming.FileName)
localPath, saveErr := saveIncomingFile("files", incoming.FileName, incoming.FileBytes)
if saveErr != nil {
if b.log != nil {
b.log.Warnf("save incoming feishu file failed name=%s err=%v", incoming.FileName, saveErr)
}
incoming.Text = buildFileRecognitionText(incoming.FileName, incoming.FileKey)
incoming.Text += "\n\n文件已下载但本地保存失败: " + saveErr.Error()
return
}
incoming.FilePath = localPath
incoming.Text = buildFileRecognitionText(incoming.FileName, incoming.FileKey)
incoming.Text += fmt.Sprintf("\n\n文件已下载并保存到本地路径=%s大小=%d bytesmime=%s。", incoming.FilePath, len(content), incoming.FileMime)
}
func (b *Bot) downloadFileContent(ctx context.Context, messageID, fileKey string) ([]byte, string, error) {
req := larkim.NewGetMessageResourceReqBuilder().
MessageId(messageID).
FileKey(fileKey).
Type("file").
Build()
resp, err := b.apiClient.Im.MessageResource.Get(ctx, req)
if err != nil {
return nil, "", err
}
if resp == nil || resp.File == nil {
if resp != nil {
return nil, "", fmt.Errorf("empty file stream code=%d msg=%s", resp.Code, resp.Msg)
}
return nil, "", fmt.Errorf("empty file stream")
}
bts, err := io.ReadAll(resp.File)
if err != nil {
return nil, "", err
}
if len(bts) > maxFeishuFileBytes {
return nil, "", fmt.Errorf("file too large: %d bytes, max=%d", len(bts), maxFeishuFileBytes)
}
return bts, strings.TrimSpace(resp.FileName), nil
}
func detectMimeByName(fileName string) string {
ext := strings.ToLower(strings.TrimSpace(filepath.Ext(fileName)))
if ext == "" {
return "application/octet-stream"
}
m := strings.TrimSpace(mime.TypeByExtension(ext))
if m == "" {
return "application/octet-stream"
}
return m
}
func saveIncomingFile(baseDir, fileName string, content []byte) (string, error) {
if len(content) == 0 {
return "", fmt.Errorf("empty file content")
}
if strings.TrimSpace(baseDir) == "" {
baseDir = "files"
}
if err := os.MkdirAll(baseDir, 0o755); err != nil {
return "", err
}
safeName := sanitizeFileName(fileName)
if safeName == "" {
safeName = "upload.bin"
}
finalName := fmt.Sprintf("%d_%s", time.Now().UnixNano(), safeName)
target := filepath.Join(baseDir, finalName)
if err := os.WriteFile(target, content, 0o644); err != nil {
return "", err
}
abs, err := filepath.Abs(target)
if err != nil {
return target, nil
}
return abs, nil
}
func sanitizeFileName(fileName string) string {
name := strings.TrimSpace(filepath.Base(fileName))
if name == "" || name == "." || name == ".." {
return ""
}
var b strings.Builder
for _, r := range name {
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '.' || r == '_' || r == '-' {
b.WriteRune(r)
continue
}
b.WriteByte('_')
}
out := strings.TrimSpace(b.String())
if out == "" || out == "." || out == ".." {
return ""
}
if strings.HasPrefix(out, ".") {
out = "file" + out
}
return out
}
func parseIncoming(event *larkim.P2MessageReceiveV1) (IncomingMessage, bool) { func parseIncoming(event *larkim.P2MessageReceiveV1) (IncomingMessage, bool) {
if event == nil || event.Event == nil || event.Event.Message == nil || event.Event.Sender == nil || event.Event.Sender.SenderId == nil { if event == nil || event.Event == nil || event.Event.Message == nil || event.Event.Sender == nil || event.Event.Sender.SenderId == nil {
return IncomingMessage{}, false return IncomingMessage{}, false
@@ -168,12 +352,11 @@ func parseIncoming(event *larkim.P2MessageReceiveV1) (IncomingMessage, bool) {
} }
msg := event.Event.Message msg := event.Event.Message
if msg.MessageType == nil || *msg.MessageType != "text" || msg.ChatId == nil || msg.Content == nil || msg.MessageId == nil { if msg.MessageType == nil || msg.ChatId == nil || msg.Content == nil || msg.MessageId == nil {
return IncomingMessage{}, false return IncomingMessage{}, false
} }
msgType := strings.TrimSpace(*msg.MessageType)
text, err := extractText(*msg.Content) if msgType == "" {
if err != nil {
return IncomingMessage{}, false return IncomingMessage{}, false
} }
@@ -186,12 +369,33 @@ func parseIncoming(event *larkim.P2MessageReceiveV1) (IncomingMessage, bool) {
userID = *event.Event.Sender.SenderId.UnionId userID = *event.Event.Sender.SenderId.UnionId
} }
return IncomingMessage{ incoming := IncomingMessage{
MessageID: *msg.MessageId, MessageID: *msg.MessageId,
ChatID: *msg.ChatId, ChatID: *msg.ChatId,
UserID: userID, UserID: userID,
Text: text, MsgType: msgType,
}, true }
switch msgType {
case "text":
text, err := extractText(*msg.Content)
if err != nil {
return IncomingMessage{}, false
}
incoming.Text = text
return incoming, true
case "file":
fileName, fileKey, err := extractFileMeta(*msg.Content)
if err != nil {
return IncomingMessage{}, false
}
incoming.FileName = fileName
incoming.FileKey = fileKey
incoming.Text = buildFileRecognitionText(fileName, fileKey)
return incoming, true
default:
return IncomingMessage{}, false
}
} }
func (b *Bot) shouldProcessMessage(messageID string) bool { func (b *Bot) shouldProcessMessage(messageID string) bool {

View File

@@ -0,0 +1,138 @@
package feishu
import (
"encoding/json"
"os"
"path/filepath"
"strings"
"testing"
larkim "github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
)
func mustEventFromJSON(t *testing.T, raw string) *larkim.P2MessageReceiveV1 {
t.Helper()
var evt larkim.P2MessageReceiveV1
if err := json.Unmarshal([]byte(raw), &evt); err != nil {
t.Fatalf("unmarshal event json failed: %v", err)
}
return &evt
}
func TestParseIncomingText(t *testing.T) {
evt := mustEventFromJSON(t, `{
"event": {
"message": {
"message_id": "msg_text_1",
"chat_id": "chat_1",
"message_type": "text",
"content": "{\"text\":\"你好\"}"
},
"sender": {
"sender_type": "user",
"sender_id": {"open_id": "u_open_1"}
}
}
}`)
in, ok := parseIncoming(evt)
if !ok {
t.Fatal("expected text message parse success")
}
if in.MsgType != "text" {
t.Fatalf("expected msg type text, got %s", in.MsgType)
}
if in.Text != "你好" {
t.Fatalf("unexpected text: %q", in.Text)
}
}
func TestParseIncomingFile(t *testing.T) {
evt := mustEventFromJSON(t, `{
"event": {
"message": {
"message_id": "msg_file_1",
"chat_id": "chat_1",
"message_type": "file",
"content": "{\"file_key\":\"file_key_123\",\"file_name\":\"report.pdf\"}"
},
"sender": {
"sender_type": "user",
"sender_id": {"user_id": "u_id_1"}
}
}
}`)
in, ok := parseIncoming(evt)
if !ok {
t.Fatal("expected file message parse success")
}
if in.MsgType != "file" {
t.Fatalf("expected msg type file, got %s", in.MsgType)
}
if in.FileName != "report.pdf" || in.FileKey != "file_key_123" {
t.Fatalf("unexpected file meta: name=%q key=%q", in.FileName, in.FileKey)
}
if !strings.Contains(in.Text, "飞书文件消息") {
t.Fatalf("expected synthesized text mentions file message, got: %q", in.Text)
}
}
func TestParseIncomingUnsupportedType(t *testing.T) {
evt := mustEventFromJSON(t, `{
"event": {
"message": {
"message_id": "msg_image_1",
"chat_id": "chat_1",
"message_type": "image",
"content": "{\"image_key\":\"img_1\"}"
},
"sender": {
"sender_type": "user",
"sender_id": {"open_id": "u_open_1"}
}
}
}`)
_, ok := parseIncoming(evt)
if ok {
t.Fatal("expected unsupported message type rejected")
}
}
func TestDetectMimeByName(t *testing.T) {
if got := detectMimeByName("report.pdf"); !strings.Contains(got, "pdf") {
t.Fatalf("expected pdf mime, got: %s", got)
}
if got := detectMimeByName("unknown.custom"); got != "application/octet-stream" {
t.Fatalf("expected octet-stream fallback, got: %s", got)
}
}
func TestSaveIncomingFile(t *testing.T) {
dir := t.TempDir()
path, err := saveIncomingFile(dir, "report.pdf", []byte("hello"))
if err != nil {
t.Fatalf("saveIncomingFile error: %v", err)
}
b, err := os.ReadFile(path)
if err != nil {
t.Fatalf("read saved file failed: %v", err)
}
if string(b) != "hello" {
t.Fatalf("unexpected saved content: %q", string(b))
}
if filepath.Ext(path) != ".pdf" {
t.Fatalf("expected .pdf extension, got: %s", path)
}
}
func TestSanitizeFileName(t *testing.T) {
got := sanitizeFileName("../bad path/测 试?.pdf")
if strings.Contains(got, "/") || strings.Contains(got, "\\") {
t.Fatalf("expected sanitized basename only, got: %q", got)
}
if !strings.HasSuffix(got, ".pdf") {
t.Fatalf("expected .pdf suffix, got: %q", got)
}
}

View File

@@ -0,0 +1,29 @@
---
name: architecture-wbs-breakdown
description: 作为架构师,将复杂需求拆解为多团队 WBS 详细文档,并自动提交至 Git 仓库
---
# 复杂系统需求拆解与多团队 WBS 规划
## 使用场景
当接收到业务需求文档,需要进行工程化拆解并进行版本化归档时使用,例如:
- 将单体需求拆解为适合多团队并行开发的 SAFe/PI 规划 WBS
- 界定系统中不同子系统(或软硬件团队)的交互边界与契约
- 将生成的拆解报告自动化落地并推送到远程代码仓库
## 架构拆分与团队规划
- 提取核心业务流程与全局非功能性需求 (NFR)
- 运用限界上下文划分独立演进的子系统明确交互契约API、RPC、ICD 等)
- 为每个子系统配置专属开发团队定义角色配置SM, PO, 开发, 测试)
## WBS 拆解与输出约束
- 按 Epic -> Feature -> Story/Task 的敏捷层级,输出结构清晰、详细的 Markdown 文档
- 明确跨团队的交付物契约,梳理 Feature 依赖关系以识别集成风险点
## 文档归档与版本控制 (工作流执行)
文档生成完毕后,必须触发以下自动化流程:
- **文件保存**:将生成的 Markdown 文档以合适的命名(如 `wbs_规划_[日期].md`)写入本地的 `new_floder` 文件夹中。
- **版本追踪**:使用 Git 管理该文件夹,执行 `git add .`(或指定该 md 文件)。
- **提交变更**:生成准确的提交信息(例如 `docs: add WBS breakdown for [项目/需求简述]`),执行 `git commit`
- **远程同步**:将本地提交推送到远程 Git 仓库,执行 `git push`

149
tools/git/git.go Normal file
View File

@@ -0,0 +1,149 @@
package git
import (
"context"
"fmt"
"os/exec"
"path/filepath"
"strings"
"time"
"laodingbot/internal/logger"
)
// Tool provides common Git operations through a safe command whitelist.
type Tool struct {
repoDir string
allowedSubcmds map[string]struct{}
timeout time.Duration
maxOutputChars int
log *logger.Logger
}
// New creates a new git tool.
func New(repoDir string, timeout time.Duration, maxOutputChars int, log *logger.Logger) *Tool {
absRepo, err := filepath.Abs(strings.TrimSpace(repoDir))
if err != nil {
absRepo = strings.TrimSpace(repoDir)
}
if timeout <= 0 {
timeout = 20 * time.Second
}
if maxOutputChars <= 0 {
maxOutputChars = 4000
}
allowed := map[string]struct{}{
"status": {},
"log": {},
"show": {},
"diff": {},
"branch": {},
"checkout": {},
"switch": {},
"restore": {},
"add": {},
"commit": {},
"reset": {},
"revert": {},
"merge": {},
"rebase": {},
"cherry-pick": {},
"fetch": {},
"pull": {},
"push": {},
"remote": {},
"tag": {},
"stash": {},
"blame": {},
"rev-parse": {},
}
if log != nil {
log.Infof("git tool initialized repo_dir=%s timeout=%s max_output_chars=%d", absRepo, timeout, maxOutputChars)
}
return &Tool{
repoDir: absRepo,
allowedSubcmds: allowed,
timeout: timeout,
maxOutputChars: maxOutputChars,
log: log,
}
}
func (t *Tool) Name() string { return "git" }
func (t *Tool) Description() string {
return "Run common git commands inside repository. Input examples: status --short | log --oneline -n 10 | add . | commit -m fix | branch"
}
func (t *Tool) Call(ctx context.Context, input string) (string, error) {
trimmed := strings.TrimSpace(input)
if trimmed == "" {
if t.log != nil {
t.log.Warnf("git tool rejected empty command")
}
return "", fmt.Errorf("empty git command")
}
parts := strings.Fields(trimmed)
if len(parts) == 0 {
return "", fmt.Errorf("empty git command")
}
if strings.EqualFold(parts[0], "git") {
parts = parts[1:]
}
if len(parts) == 0 {
return "", fmt.Errorf("missing git subcommand")
}
subcmd := strings.ToLower(parts[0])
if _, ok := t.allowedSubcmds[subcmd]; !ok {
if t.log != nil {
t.log.Warnf("git tool rejected subcommand=%s", subcmd)
}
return "", fmt.Errorf("unsupported git subcommand: %s", subcmd)
}
runCtx, cancel := context.WithTimeout(ctx, t.timeout)
defer cancel()
args := append([]string{subcmd}, parts[1:]...)
if t.log != nil {
t.log.Infof("git command start subcommand=%s args=%d full=%q", subcmd, len(parts)-1, strings.Join(args, " "))
}
cmd := exec.CommandContext(runCtx, "git", args...)
cmd.Dir = t.repoDir
cmd.Env = append(cmd.Environ(),
"GIT_TERMINAL_PROMPT=0",
"GIT_PAGER=cat",
"GIT_EDITOR=true",
)
out, err := cmd.CombinedOutput()
outText := strings.TrimSpace(string(out))
if len(outText) > t.maxOutputChars {
outText = outText[:t.maxOutputChars]
}
if err != nil {
if t.log != nil {
t.log.Errorf("git command failed subcommand=%s err=%v output=%q", subcmd, err, outText)
}
if outText == "" {
return "", err
}
return outText, err
}
if t.log != nil {
t.log.Infof("git command success subcommand=%s output_bytes=%d", subcmd, len(out))
}
if outText == "" {
return "ok", nil
}
return outText, nil
}

129
tools/git/git_test.go Normal file
View File

@@ -0,0 +1,129 @@
package git
import (
"context"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
)
func TestCallRejectsEmptyCommand(t *testing.T) {
tool := New(t.TempDir(), 3*time.Second, 4000, nil)
_, err := tool.Call(context.Background(), " ")
if err == nil {
t.Fatal("expected error for empty command")
}
}
func TestCallRejectsUnsupportedSubcommand(t *testing.T) {
repo := initTestRepo(t)
tool := New(repo, 5*time.Second, 4000, nil)
_, err := tool.Call(context.Background(), "bisect start")
if err == nil {
t.Fatal("expected unsupported subcommand error")
}
if !strings.Contains(err.Error(), "unsupported git subcommand") {
t.Fatalf("unexpected error: %v", err)
}
}
func TestStatusAndLog(t *testing.T) {
repo := initTestRepo(t)
tool := New(repo, 5*time.Second, 4000, nil)
status, err := tool.Call(context.Background(), "status --short")
if err != nil {
t.Fatalf("status failed: %v", err)
}
if strings.TrimSpace(status) != "" && status != "ok" {
t.Fatalf("expected clean status output, got: %q", status)
}
logOut, err := tool.Call(context.Background(), "git log --oneline -n 1")
if err != nil {
t.Fatalf("log failed: %v", err)
}
if !strings.Contains(logOut, "initial commit") {
t.Fatalf("expected initial commit in log output, got: %q", logOut)
}
}
func TestAddCommitAndDiff(t *testing.T) {
repo := initTestRepo(t)
tool := New(repo, 8*time.Second, 8000, nil)
file := filepath.Join(repo, "note.txt")
if err := os.WriteFile(file, []byte("v1\n"), 0o644); err != nil {
t.Fatalf("write file failed: %v", err)
}
_, err := tool.Call(context.Background(), "add note.txt")
if err != nil {
t.Fatalf("add failed: %v", err)
}
_, err = tool.Call(context.Background(), "commit -m add-note")
if err != nil {
t.Fatalf("commit failed: %v", err)
}
if err := os.WriteFile(file, []byte("v2\n"), 0o644); err != nil {
t.Fatalf("rewrite file failed: %v", err)
}
diffOut, err := tool.Call(context.Background(), "diff -- note.txt")
if err != nil {
t.Fatalf("diff failed: %v", err)
}
if !strings.Contains(diffOut, "-v1") || !strings.Contains(diffOut, "+v2") {
t.Fatalf("expected diff output with v1/v2 changes, got: %q", diffOut)
}
}
func initTestRepo(t *testing.T) string {
t.Helper()
if _, err := exec.LookPath("git"); err != nil {
t.Skip("git is not installed")
}
repo := t.TempDir()
runGit(t, repo, "init")
runGit(t, repo, "config", "user.name", "test-user")
runGit(t, repo, "config", "user.email", "test@example.com")
readme := filepath.Join(repo, "README.md")
if err := os.WriteFile(readme, []byte("hello\n"), 0o644); err != nil {
t.Fatalf("write readme failed: %v", err)
}
runGit(t, repo, "add", "README.md")
runGit(t, repo, "commit", "-m", "initial commit")
return repo
}
func runGit(t *testing.T, repo string, args ...string) {
t.Helper()
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
cmd := exec.CommandContext(ctx, "git", args...)
cmd.Dir = repo
cmd.Env = append(cmd.Environ(),
"GIT_TERMINAL_PROMPT=0",
"GIT_PAGER=cat",
"GIT_EDITOR=true",
)
if runtime.GOOS == "windows" {
// Keep default behavior; this branch documents cross-platform intent.
}
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("git %s failed: %v\n%s", strings.Join(args, " "), err, string(out))
}
}

View File

@@ -94,6 +94,9 @@ func (t *Tool) Call(ctx context.Context, input string) (string, error) {
if runtime.GOOS == "windows" { if runtime.GOOS == "windows" {
// Windows 下使用 cmd /C 执行,兼容 date、dir 等内建命令。 // Windows 下使用 cmd /C 执行,兼容 date、dir 等内建命令。
cmd = exec.CommandContext(runCtx, "cmd", "/C", trimmed) cmd = exec.CommandContext(runCtx, "cmd", "/C", trimmed)
} else if requiresShellParsing(trimmed) {
// 包含管道、重定向等语法时,必须交给 shell 解释。
cmd = exec.CommandContext(runCtx, "sh", "-c", trimmed)
} else { } else {
cmd = exec.CommandContext(runCtx, base, parts[1:]...) cmd = exec.CommandContext(runCtx, base, parts[1:]...)
} }
@@ -126,3 +129,7 @@ func normalizeWindowsCommand(command string) string {
return command return command
} }
} }
func requiresShellParsing(command string) bool {
return strings.ContainsAny(command, "|&;<>()$`\\\n")
}

View File

@@ -40,3 +40,27 @@ func TestCallWindowsDateIsNonInteractive(t *testing.T) {
t.Fatal("expected non-empty output for date command") t.Fatal("expected non-empty output for date command")
} }
} }
func TestRequiresShellParsing(t *testing.T) {
if !requiresShellParsing("echo hi | cat") {
t.Fatal("expected pipe command to require shell parsing")
}
if requiresShellParsing("echo hello") {
t.Fatal("expected simple command to not require shell parsing")
}
}
func TestCallSupportsPipeOnUnix(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("unix-only behavior test")
}
tool := New([]string{"echo"}, ".", 3*time.Second, 4000, nil)
out, err := tool.Call(context.Background(), "printf hello | wc -c")
if err != nil {
t.Fatalf("expected pipeline command success, got err=%v output=%q", err, out)
}
trimmed := strings.TrimSpace(out)
if trimmed != "5" {
t.Fatalf("expected output 5, got %q", trimmed)
}
}